Factory method
The factory pattern is a design pattern used to promote encapsulation of data representation.
- Problem
- We want to decide at run time what object is to be created based on some configuration or application parameter. When we write the code we do not know what class should be instantiated.
- Solution
- Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. Its primary purpose is to provide a way for users to retrieve an instance with a known compile-time type, but whose runtime type may actually be different. In other words, a factory method that is supposed to return an instance of the class Foo may return an instance of the class Foo, or it may return an instance of the class Bar, so long as Bar inherits from Foo. The reason for this is that it strengthens the boundary between implementor and client, hiding the true representation of the data (see Abstraction Barrier) from the user, thereby allowing the implementor to change this representation at anytime without affecting the client, as long as the client facing interface doesn't change.
Basic Implementation of the Factory Pattern
The general template for implementing the factory pattern is to provide a primary user facing class with static methods which the user can use to get instances with that type. Constructors are then made private/protected from the user, forcing them to use the static factory methods to get objects. The following Java code shows a very simple implementation of the factory pattern for type Foo.
public class Foo {
// Static factory method
public static Foo getInstance() {
// Inside this class, we have access to private methods
return new Foo();
}
// Guarded constructor, only accessible from within this class, since it's marked private
private Foo() {
// Typical initialization code goes here
}
} // End class Foo
With this code, it would be impossible for a client of the code to use the new operator to get an instance of the class, as is traditionally done:
// Client code
Foo f = new Foo(); // Won't Work!
because the constructor is marked private. Instead, the client would have to use the factory method:
// Client code
Foo f = Foo.getInstance(); // Works!
It should be noted that even within a programming language community, there is no general consensus as to the naming convention of a factory method. Some suggest naming the method with the name of the class, similar to a normal constructor, but starting with a lowercase. Others say that this is confusing, and suggest using an accessor type syntax, like the getInstance style used above, though others complain that this may incorrectly imply a singleton implementation. Likewise, some offer newInstance, but this is criticized as being misleading in certain situations where a strictly new instance may not actually be returned (once again, refer to the singleton pattern). As such, we will not attempt to follow any particularly rigid standard here, we will simply try to use a name that makes the most sense for our current purposes.
Factory Pattern Implementation of the Alphabet
That's great, you know how to implement a real simple factory pattern, but what good did it do you? Users are asking for something that fits into type Foo, and they're getting an instance of the class Foo, how is that different from just calling the constructor? Well it's not, except that you're putting another function call on the stack (which is a bad thing). But that's only for the above case. We'll now discuss a more useful use of the factory pattern. Consider a simple type called Letter, representing a letter in the alphabet, which has the following client facing interface (i.e., public instance methods):
char toCharacter();
boolean isVowel();
boolean isConsonant();
We could implement this easily enough without using the factory method, which might start out something like this:
public class Letter {
private char fTheLetter;
public Letter(char aTheLetter) {
fTheLetter = aTheLetter;
}
public char toCharacter() {
return fTheLetter;
}
public boolean isVowel() {
//TODO: we haven't implemented this yet
return true;
}
public boolean isConsonant() {
// TODO: we haven't implemented this yet
return false;
}
} // End class Letter
Fairly simple, but notice we haven't implemented the last two methods yet. We can still do it pretty easily. The first might look like this:
public boolean isVowel() {
return
fTheLetter == 'a' ||
fTheLetter == 'e' ||
fTheLetter == 'i' ||
fTheLetter == 'o' ||
fTheLetter == 'u' ||
fTheLetter == 'A' ||
fTheLetter == 'E' ||
fTheLetter == 'I' ||
fTheLetter == 'O' ||
fTheLetter == 'U';
}
Now that's not too bad, but we still need to do isConsonant. Fortunately, we at least know in this case that if it's a vowel, it's not a consonant, and vice versa, so our last method could simply be:
public boolean isConsonant() {
return !this.isVowel();
}
So what's the problem here? Basically, every time you call either of these methods, your program has to do all that checking. Granted, this isn't a real heavy burden for the Java Runtime Environment, but you can imagine a much more complex, much more time consuming operation. Wouldn't it be great if we could avoid doing this every time we call the method? Let's say, for instance, we could do it once when we create the object, and then not have to do it again. Well sure, we can do that. Here's an implementation that'll do that for us, and we still don't have to use the factory method:
public class Letter {
private char fTheLetter;
private boolean fIsVowel;
public Letter(char aTheLetter) {
fTheLetter = aTheLetter;
fIsVowel = fTheLetter == 'a' ||
fTheLetter == 'e' ||
fTheLetter == 'i' ||
fTheLetter == 'o' ||
fTheLetter == 'u' ||
fTheLetter == 'A' ||
fTheLetter == 'E' ||
fTheLetter == 'I' ||
fTheLetter == 'O' ||
fTheLetter == 'U';
}
public char toCharacter() {
return fTheLetter;
}
public boolean isVowel() {
return fIsVowel;
}
public boolean isConsonant() {
return !fIsVowel;
}
} // End class Letter
Notice how we moved the lengthy operation into the constructor, and stored the result. OK, so now we're all fine and dandy, no? Sure, but let's say you came up with a new idea, a different implementation: you want to split this type into two classes, one class to handle the vowels, and one to handle the consonants. Great, they can both be subclasses of the Letter class, and the user will never know the difference, right? Wrong. How is the client supposed to get at these new classes? They've got code that works perfectly well for them by calling new Letter('a') and new Letter('Z'). Now you're going to make them go through all their code and change these to new Vowel('a') and new Consonant('Z')? They probably won't be too happy with that. If only you could get new instances of both classes from one method! Well you can, just use a static method in the Letter class, it'll do the same one-time checking as the constructor did, and will return an appropriate instance of the right class. And what do you know, it's a factory method! But that still doesn't do your client much good, they still need to go through and change all the new Letter()s into Letter.getLetter(). Well, sad to say, it's too late to help them at all, unless you just give up your new implementation. But that illustrates the reason for using the factory method right off the bat. One of the key components of good object oriented programming is that you never know exactly where your code will go in the future. By making good use of the abstraction barrier and using encapsulation-friendly programming patterns, such as the factory pattern, you can better prepare yourself—and your client—for future changes to the specific implementation. In particular, it allows you to use a "big hammer" kind of approach to get something done in a perhaps-less-than-ideal but rapid manner in order to meet deadlines or move ahead with testing,. You can then go back later and refine the implementation—the data representation and algorithms—to be faster, smaller, or what-have-you, and as long as you maintained the abstraction barrier between implementor and client and properly encapsulated your implementation, then you can change it without requiring the client to change any of their code. Well now that I'm sure you're a raving advocate for the factory method, let's take a look at how we would implement it for our Letter type:
public abstract class Letter {
// Factory Method
public static Letter getLetter(char aTheLetter) {
// Like before, we do a one time check to see what kind of
// letter we are dealing with. Only this time, instead of setting
// a property to track it, we actually have a different class for each
// of the two letter types.
if (
aTheLetter == 'a' ||
aTheLetter == 'e' ||
aTheLetter == 'i' ||
aTheLetter == 'o' ||
aTheLetter == 'u' ||
aTheLetter == 'A' ||
aTheLetter == 'E' ||
aTheLetter == 'I' ||
aTheLetter == 'O' ||
aTheLetter == 'U'
) {
return new Vowel(aTheLetter);
} else {
return new Consonant(aTheLetter);
}
}
// User facing interface
// We make these methods abstract, thereby requiring all subclasses
// (actually, just all concrete subclasses, that is, non-abstract)
// to implement the methods.
public abstract boolean isVowel();
public abstract boolean isConsonant();
public abstract char getChar();
// Now we define the two concrete classes for this type,
// the ones that actually implement the type.
private static class Vowel extends Letter {
private char iTheLetter;
// Constructor
Vowel(char aTheLetter) {
this.iTheLetter = aTheLetter;
}
// Nice easy implementation of this method!
public boolean isVowel() {
return true;
}
// This one, too!
public boolean isConsonant() {
return false;
}
public char getLetter(){
return iTheLetter;
}
} // End local class Vowel
private static class Consonant extends Letter {
private char iTheLetter;
// Constructor
Consonant(char aTheLetter) {
this.iTheLetter = aTheLetter;
}
public boolean isVowel() {
return false;
}
public boolean isConsonant(){
return true;
}
public char getLetter(){
return iTheLetter;
}
} // End local class Consonant
} // End toplevel class Letter
Several things to note here.
- First, you'll notice the top level class Letter is abstract. This is fine because you'll notice that it doesn't actually do anything except define the interface and provide a top level container for the two other classes. However, it's also important (not just OK) to make this abstract because we don't want people trying to instantiate the Letter class directly. Of course we could solve this problem by making a private constructor, but making the class abstract instead is cleaner, and makes it more obvious that the Letter class is not meant to be instantiated. It also, as mentioned, allows us to define the user facing interface that the work horse classes need to implement.
- The two nested classes we created are called local classes, which is basically the same as an inner class except that local classes are static, and inner classes are not. They have to be static so that our static factory method can create them. If they were non static (i.e., dynamic) then they could only be accessed through an instance of the Letter class, which we can never have because Letter is abstract. Also note that (in Java, anyway) the fields for inner and local classes typically use the "i" (for inner) prefix, as opposed to the "f" (for field) prefix used by top level classes. This is simply a naming convention used by many Java programmers and doesn't actually effect the program.
- The two nested classes that implement the Letter data type do not actually have to be local/inner. They could just have easily been top level classes that extend the abstract Letter class. However, this is contrary to the point of the factory pattern, which is encapsulation. Top level classes can't be private in Java, because that doesn't make any sense (what are they private to?) and the whole point is that no client has to (or should, really) know how the type is implemented. Making these classes top level allows clients to potentially stumble across them, and worse yet, instantiate them, by-passing the factory pattern all together.
- Lastly, this is not very good code. There's a lot of ways we can make it better to really illustrate the power of the factory pattern. I'll discuss these refactorings briefly, and then show another, more polished, version of the above code which includes a lot of them.
Refactoring the Factory Pattern
Notice that both of the local classes do the same thing in a few places. This is redundant code which is not only more work to write, but it's also highly discouraged in object oriented programming (partially because it takes more work to write, but mostly because it's harder to maintain and prone to errors, e.g., you find a bug in the code and change it in one spot, but forget to in another.) Below is a list of redundancies in the above code:
- The field iTheLetter
- The method getLetter()
- The constructor of each inner class does the same thing.
In addition, as we discovered above, the isVowel() and isConsonant() just happen to always return the opposite of each other for a given instance. However, since this is something of a peculiarity for this particular example, we won't worry about it. The lesson you would learn from us doing that will already be covered in the refactoring of the getLetter() method. OK, so we have redundant code in two classes. If you're familiar with abstracting processes, then this is probably a familiar scenario to you. Often, having redundant code in two different classes makes them prime candidates for abstraction, meaning that a new abstract class is created to implement the redundant code, and the two classes simply extend this new abstract class instead of implementing the redundant code. Well what do you know? We already have an abstract super class that our redundant classes have in common. All we have to do is make the super class implement the redundant code, and the other classes will automatically inherit this implementation, as long as we don't override it. So that works fine for the getLetter() method, we can move both the method and the iTheLetter field up to the abstract parent class. But what about the constructors? Well our constructor takes an argument, so we won't automatically inherit it, that's just the way java works. But we can use the super keyword to automatically delegate to the super classes constructor. In other words, we'll implement the constructor in the super class, since that's where the field is anyway, and the other two classes will delegate to this method in their own constructors. For our example, this doesn't save much work, we're replacing a one line assignment with a one line call to super(), but in theory, there could be hundred of lines of code in the constructors, and moving it up could be a great help. At this point, you might be a little worried about putting a constructor in the Letter class. Didn't I already say not to do that? I thought we didn't want people trying to instantiate Letter directly? Don't worry, the class is still abstract. Even if there's a concrete constructor, Java won't let you instantiate an abstract class, because it's abstract, it could have method that are accessible but undefined, and it wouldn't know what to do if such a method was invoked. So putting the constructor in is fine. After making the above refactorings, our code now looks like this:
public abstract class Letter {
// Factory Method
public static Letter getLetter(char aTheLetter){
if (
aTheLetter == 'a' ||
aTheLetter == 'e' ||
aTheLetter == 'i' ||
aTheLetter == 'o' ||
aTheLetter == 'u' ||
aTheLetter == 'A' ||
aTheLetter == 'E' ||
aTheLetter == 'I' ||
aTheLetter == 'O' ||
aTheLetter == 'U'
) {
return new Vowel(aTheLetter);
} else {
return new Consonant(aTheLetter);
}
}
// Our new abstracted field. We'll make it protected so that subclasses can see it,
// and we rename it from "i" to "f", following our naming convention.
protected char fTheLetter;
// Our new constructor. It can't actually be used to instantiate an instance
// of Letter, but our sub classes can invoke it with super
protected Letter(char aTheLetter) {
this.fTheLetter = aTheLetter;
}
// The new method we're abstracting up to remove redundant code in the sub classes
public char getChar() {
return this.fTheLetter;
}
// Same old abstract methods that define part of our client facing interface
public abstract boolean isVowel();
public abstract boolean isConsonant();
// The local subclasses with the redundant code moved up.
private static class Vowel extends Letter {
// Constructor delegates to the super constructor
Vowel(char aTheLetter) {
super(aTheLetter);
}
// Still need to implement the abstract methods
public boolean isVowel() {
return true;
}
public boolean isConsonant(){
return false;
}
} // End local class Vowel
private static class Consonant extends Letter {
Consonant(char aTheLetter){
super(aTheLetter);
}
public boolean isVowel(){
return false;
}
public boolean isConsonant(){
return true;
}
} // End local class Consonant
} // End toplevel class Letter
Note that we made our abstracted field protected. This isn't strictly necessary in this case, we could have left it private, because the subclasses don't actually need to access it at all. In general, I prefer to make things protected instead of private, since, as I mentioned, you can never really be sure where a project will go in the future, and you may not want to restrict future implementors (including yourself) unnecessarily. However, many people prefer to default to private and only use protected when they know it's necessary. A major reason for this is the rather peculiar and somewhat unexpected meaning of protected in Java, which allows not only subclasses, but anything in the same package to access it. This is a bit of a digression, but I think it's a fairly important debate that a good Java programmer should be aware of.
The Factory Pattern and Parametric Polymorphism
The version of the Java Virtual Machine 5.0 has introduced something called Parametric Polymorphism, which goes by many other names in other languages, including "generic typing" in C++. In order to really understand the rest of this section, you should read that section first. But basically, this means that you can introduce additional parameters into a class—parameters which are set at instantiation—that define the types of certain elements in the class, for instance fields or method return values. This is a very powerful tool which allows programmers to avoid a lot of those nasty instanceofs and narrowing castes. However, the implementation of this device in the JVM does not promote the use of the Factory pattern, and in the two do not play well together. This is because Java does not allow methods to be parameterized the way types are, so you cannot dynamically parameterize an instance through a method, only through use of the new operator. As an example, imagine a type Foo which is parameterized with a single type which we'll call T. In java we would write this class like this:
class Foo<T> {
} // End class Foo
Now we can have instances of Foo parameterized by all sorts of types, for instance:
Foo<String> fooOverString = new Foo<String>();
Foo<Integer> fooOverInteger = new Foo<Integer>();
But let's say we want to use the factory pattern for Foo. How do we do that? You could create a different factory method for each type you want to parameterize over, for instance:
class Foo<T> {
static Foo<String> getFooOverString() {
return new Foo<String>();
}
static Foo<Integer> getFooOverInteger() {
return new Foo<Integer>();
}
} // End class Foo
But what about something like the ArrayList class (in the java.util package)? In the java standard libraries released with 5.0, ArrayList is parameterized to define the type of the object stored in it. We certainly don't want to restrict what kinds of types it can be parameterized with by having to write a factory method for each type. This is often the case with parameterized types: you don't know what types users will want to parameterize with, and you don't want to restrict them, so the factory pattern won't work for that. You are allowed to instantiate a parameterized type in a generic form, meaning you don't specify the parameter at all, you just instantiate it the way you would have before 5.0. But that forces you to give up the parameterization. This is how you do it with generics:
class Foo<T> {
public static <E> Foo<E> getFoo() {
return new Foo<E>();
}
} // End class Foo
Examples
In Java, a class that implements java.sql.Connection
is a factory of statements. By calling the createStatement()
method, you create a statement for which you only know the interface. The factory chooses the right instance class for you.
Cost
This pattern is not so expensive when it is implemented at the right time. It can be more expensive if you have to refactor an existing code.
Creation
Its implementation is easy and there is no additional cost (it is not more expensive than an implementation without this pattern).
Maintenance
There is no additional cost nor additional constraint.
Removal
This pattern can be easily removed as automatic refactoring operations can easily remove its existence.
Good practices
- Name the factory class with the instanciated class in prefix and the factory term in suffix, to indicate the use of the pattern to the other developers.
- Avoid to persist the factory result (in database) into the factory class, to respect the SOLID principles and allow the creation of ephemeral objects, for example into the automatic tests.
Implementation
REPORT zz_pizza_factory_test NO STANDARD PAGE HEADING .
TYPES ty_pizza_type TYPE i .
*----------------------------------------------------------------------*
* CLASS lcl_pizza DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_pizza DEFINITION ABSTRACT .
PUBLIC SECTION .
DATA p_pizza_name TYPE string .
METHODS get_price ABSTRACT
RETURNING value(y_price) TYPE i .
ENDCLASS . "lcl_pizza DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_ham_and_mushroom_pizza DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_ham_and_mushroom_pizza DEFINITION INHERITING FROM lcl_pizza .
PUBLIC SECTION .
METHODS constructor .
METHODS get_price REDEFINITION .
ENDCLASS . "lcl_ham_and_mushroom_pizza DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_deluxe_pizza DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_deluxe_pizza DEFINITION INHERITING FROM lcl_pizza .
PUBLIC SECTION .
METHODS constructor .
METHODS get_price REDEFINITION .
ENDCLASS . "lcl_ham_and_mushroom_pizza DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_hawaiian_pizza DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_hawaiian_pizza DEFINITION INHERITING FROM lcl_pizza .
PUBLIC SECTION .
METHODS constructor .
METHODS get_price REDEFINITION .
ENDCLASS . "lcl_ham_and_mushroom_pizza DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_pizza_factory DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_pizza_factory DEFINITION .
PUBLIC SECTION .
CONSTANTS: BEGIN OF co_pizza_type ,
ham_mushroom TYPE ty_pizza_type VALUE 1 ,
deluxe TYPE ty_pizza_type VALUE 2 ,
hawaiian TYPE ty_pizza_type VALUE 3 ,
END OF co_pizza_type .
CLASS-METHODS create_pizza IMPORTING x_pizza_type TYPE ty_pizza_type
RETURNING value(yo_pizza) TYPE REF TO lcl_pizza
EXCEPTIONS ex_invalid_pizza_type .
ENDCLASS . "lcl_pizza_factory DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_ham_and_mushroom_pizza
*----------------------------------------------------------------------*
CLASS lcl_ham_and_mushroom_pizza IMPLEMENTATION .
METHOD constructor .
super->constructor( ) .
p_pizza_name = 'Ham & Mushroom Pizza'(001) .
ENDMETHOD . "constructor
METHOD get_price .
y_price = 850 .
ENDMETHOD . "get_price
ENDCLASS . "lcl_ham_and_mushroom_pizza IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS lcl_deluxe_pizza IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_deluxe_pizza IMPLEMENTATION .
METHOD constructor .
super->constructor( ) .
p_pizza_name = 'Deluxe Pizza'(002) .
ENDMETHOD . "constructor
METHOD get_price .
y_price = 1050 .
ENDMETHOD . "get_price
ENDCLASS . "lcl_deluxe_pizza IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS lcl_hawaiian_pizza IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_hawaiian_pizza IMPLEMENTATION .
METHOD constructor .
super->constructor( ) .
p_pizza_name = 'Hawaiian Pizza'(003) .
ENDMETHOD . "constructor
METHOD get_price .
y_price = 1150 .
ENDMETHOD . "get_price
ENDCLASS . "lcl_hawaiian_pizza IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS lcl_pizza_factory IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_pizza_factory IMPLEMENTATION .
METHOD create_pizza .
CASE x_pizza_type .
WHEN co_pizza_type-ham_mushroom .
CREATE OBJECT yo_pizza TYPE lcl_ham_and_mushroom_pizza .
WHEN co_pizza_type-deluxe .
CREATE OBJECT yo_pizza TYPE lcl_deluxe_pizza .
WHEN co_pizza_type-hawaiian .
CREATE OBJECT yo_pizza TYPE lcl_hawaiian_pizza .
ENDCASE .
ENDMETHOD . "create_pizza
ENDCLASS . "lcl_pizza_factory IMPLEMENTATION
START-OF-SELECTION .
DATA go_pizza TYPE REF TO lcl_pizza .
DATA lv_price TYPE i .
DO 3 TIMES .
go_pizza = lcl_pizza_factory=>create_pizza( sy-index ) .
lv_price = go_pizza->get_price( ) .
WRITE:/ 'Price of', go_pizza->p_pizza_name, 'is £', lv_price LEFT-JUSTIFIED .
ENDDO .
*Output:
*Price of Ham & Mushroom Pizza is £ 850
*Price of Deluxe Pizza is £ 1.050
*Price of Hawaiian Pizza is £ 1.150
public class Pizza
{
protected var _price:Number;
public function get price():Number
{
return _price;
}
}
public class HamAndMushroomPizza extends Pizza
{
public function HamAndMushroomPizza()
{
_price = 8.5;
}
}
public class DeluxePizza extends Pizza
{
public function DeluxePizza()
{
_price = 10.5;
}
}
public class HawaiianPizza extends Pizza
{
public function HawaiianPizza()
{
_price = 11.5;
}
}
public class PizzaFactory
{
static public function createPizza(type:String):Pizza
{
switch (type)
{
case "HamAndMushroomPizza":
return new HamAndMushroomPizza();
break;
case "DeluxePizza":
return new DeluxePizza();
break;
case "HawaiianPizza":
return new HawaiianPizza();
break;
default:
throw new ArgumentError("The pizza type " + type + " is not recognized.");
}
}
}
public class Main extends Sprite
{
public function Main()
{
for each (var pizza:String in ["HamAndMushroomPizza", "DeluxePizza", "HawaiianPizza"])
{
trace("Price of " + pizza + " is " + PizzaFactory.createPizza(pizza).price);
}
}
}
Output:
Price of HamAndMushroomPizza is 8.5
Price of DeluxePizza is 10.5
Price of HawaiianPizza is 11.5
This C++11 implementation is based on the pre C++98 implementation in the book.
#include <iostream>
enum Direction {North, South, East, West};
class MapSite {
public:
virtual void enter() = 0;
virtual ~MapSite() = default;
};
class Room : public MapSite {
public:
Room() :roomNumber(0) {}
Room(int n) :roomNumber(n) {}
void setSide(Direction d, MapSite* ms) {
std::cout << "Room::setSide " << d << ' ' << ms << '\n';
}
virtual void enter() {}
Room(const Room&) = delete; // rule of three
Room& operator=(const Room&) = delete;
private:
int roomNumber;
};
class Wall : public MapSite {
public:
Wall() {}
virtual void enter() {}
};
class Door : public MapSite {
public:
Door(Room* r1 = nullptr, Room* r2 = nullptr)
:room1(r1), room2(r2) {}
virtual void enter() {}
Door(const Door&) = delete; // rule of three
Door& operator=(const Door&) = delete;
private:
Room* room1;
Room* room2;
};
class Maze {
public:
void addRoom(Room* r) {
std::cout << "Maze::addRoom " << r << '\n';
}
Room* roomNo(int) const {
return nullptr;
}
};
// If createMaze calls virtual functions instead of constructor calls to create the rooms, walls, and doors it requires, then you can change the classes that get instantiated by making a subclass of MazeGame and redefining those virtual functions. This approach is an example of the Factory Method (121) pattern.
class MazeGame {
public:
Maze* createMaze () {
Maze* aMaze = makeMaze();
Room* r1 = makeRoom(1);
Room* r2 = makeRoom(2);
Door* theDoor = makeDoor(r1, r2);
aMaze->addRoom(r1);
aMaze->addRoom(r2);
r1->setSide(North, makeWall());
r1->setSide(East, theDoor);
r1->setSide(South, makeWall());
r1->setSide(West, makeWall());
r2->setSide(North, makeWall());
r2->setSide(East, makeWall());
r2->setSide(South, makeWall());
r2->setSide(West, theDoor);
return aMaze;
}
// factory methods:
virtual Maze* makeMaze() const {
return new Maze;
}
virtual Room* makeRoom(int n) const {
return new Room(n);
}
virtual Wall* makeWall() const {
return new Wall;
}
virtual Door* makeDoor(Room* r1, Room* r2) const {
return new Door(r1, r2);
}
virtual ~MazeGame() = default;
};
int main() {
MazeGame game;
game.createMaze();
}
The program output is like:
Maze::addRoom 0xcaced0
Maze::addRoom 0xcacef0
Room::setSide 0 0xcad340
Room::setSide 2 0xcacf10
Room::setSide 1 0xcad360
Room::setSide 3 0xcad380
Room::setSide 0 0xcad3a0
Room::setSide 2 0xcad3c0
Room::setSide 1 0xcad3e0
Room::setSide 3 0xcacf10
In Common Lisp, factory methods are not really needed, because classes and class names are first class values.
(defclass pizza ()
((price :accessor price)))
(defclass ham-and-mushroom-pizza (pizza)
((price :initform 850)))
(defclass deluxe-pizza (pizza)
((price :initform 1050)))
(defclass hawaiian-pizza (pizza)
((price :initform 1150)))
(defparameter *pizza-types*
(list 'ham-and-mushroom-pizza
'deluxe-pizza
'hawaiian-pizza))
(loop for pizza-type in *pizza-types*
do (format t "~%Price of ~a is ~a"
pizza-type
(price (make-instance pizza-type))))
Output:
Price of HAM-AND-MUSHROOM-PIZZA is 850
Price of DELUXE-PIZZA is 1050
Price of HAWAIIAN-PIZZA is 1150
program FactoryMethod;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
// Product
TProduct = class(TObject)
public
function GetName(): string; virtual; abstract;
end;
// ConcreteProductA
TConcreteProductA = class(TProduct)
public
function GetName(): string; override;
end;
// ConcreteProductB
TConcreteProductB = class(TProduct)
public
function GetName(): string; override;
end;
// Creator
TCreator = class(TObject)
public
function FactoryMethod(): TProduct; virtual; abstract;
end;
// ConcreteCreatorA
TConcreteCreatorA = class(TCreator)
public
function FactoryMethod(): TProduct; override;
end;
// ConcreteCreatorB
TConcreteCreatorB = class(TCreator)
public
function FactoryMethod(): TProduct; override;
end;
{ ConcreteProductA }
function TConcreteProductA.GetName(): string;
begin
Result := 'ConcreteProductA';
end;
{ ConcreteProductB }
function TConcreteProductB.GetName(): string;
begin
Result := 'ConcreteProductB';
end;
{ ConcreteCreatorA }
function TConcreteCreatorA.FactoryMethod(): TProduct;
begin
Result := TConcreteProductA.Create();
end;
{ ConcreteCreatorB }
function TConcreteCreatorB.FactoryMethod(): TProduct;
begin
Result := TConcreteProductB.Create();
end;
const
Count = 2;
var
Creators: array[1..Count] of TCreator;
Product: TProduct;
I: Integer;
begin
// An array of creators
Creators[1] := TConcreteCreatorA.Create();
Creators[2] := TConcreteCreatorB.Create();
// Iterate over creators and create products
for I := 1 to Count do
begin
Product := Creators[I].FactoryMethod();
WriteLn(Product.GetName());
Product.Free();
end;
for I := 1 to Count do
Creators[I].Free();
ReadLn;
end.
Example with pizza
abstract class Pizza {
public abstract int getPrice(); // Count the cents
}
class HamAndMushroomPizza extends Pizza {
public int getPrice() {
return 850;
}
}
class DeluxePizza extends Pizza {
public int getPrice() {
return 1050;
}
}
class HawaiianPizza extends Pizza {
public int getPrice() {
return 1150;
}
}
class PizzaFactory {
public enum PizzaType {
HamMushroom,
Deluxe,
Hawaiian
}
public static Pizza createPizza(PizzaType pizzaType) {
switch (pizzaType) {
case HamMushroom:
return new HamAndMushroomPizza();
case Deluxe:
return new DeluxePizza();
case Hawaiian:
return new HawaiianPizza();
}
throw new IllegalArgumentException("The pizza type " + pizzaType + " is not recognized.");
}
}
class PizzaLover {
/**
* Create all available pizzas and print their prices
*/
public static void main (String args[]) {
for (PizzaFactory.PizzaType pizzaType : PizzaFactory.PizzaType.values()) {
System.out.println("Price of " + pizzaType + " is " + PizzaFactory.createPizza(pizzaType).getPrice());
}
}
}
Output:
Price of HamMushroom is 850 Price of Deluxe is 1050 Price of Hawaiian is 1150
Another example with image
- Abstract creator
- Interface to create the Product.
package mypkg;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
*
* @author xxx
*/
public interface PhotoReader {
public BufferedImage getImage() throws IOException;
}
- Concrete creator
- a class to create specific Product.
package mypkg;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
/**
*
* @author xxx
*/
public class JPEGReader implements PhotoReader {
ImageReader reader;
File jpegFile;
ImageInputStream iis;
public JPEGReader(String filePath) throws IOException {
jpegFile = new File(filePath);
iis = ImageIO.createImageInputStream(jpegFile);
Iterator readers = ImageIO.getImageReadersByFormatName("jpg");
reader = (ImageReader)readers.next();
this.reader.setInput(iis, true);
}
public BufferedImage getImage() throws IOException {
return reader.read(0);
}
- Factory class
- a class to return a specific concrete creator at runtime to create the product.
package mypkg;
import java.io.IOException;
/**
*
* @author xxx
*/
public class PhotoReaderFactory {
enum Mimi {
jpg, JPG, gif, GIF, bmp, BMP, png, PNG
};
public static PhotoReader getPhotoReader(String filePath) {
String suffix = getFileSuffix(filePath);
PhotoReader reader = null;
try {
switch (Mimi.valueOf(suffix)) {
case jpg :
case JPG : reader = new JPEGReader(filePath); break;
case gif :
case GIF : reader = new GIFReader(filePath); break;
case bmp :
case BMP : reader = new BMPReader(filePath); break;
case png :
case PNG : reader = new PNGReader(filePath); break;
default : break;
}
} catch(IOException io) {
io.printStackTrace();
}
return reader;
}
private static String getFileSuffix(String filePath) {
String[] stringArray = filePath.split("\\.");
return stringArray[stringArray.length - 1];
}
}
This example in JavaScript uses Firebug console to output information.
/**
* Extends parent class with child. In Javascript, the keyword "extends" is not
* currently implemented, so it must be emulated.
* Also it is not recommended to use keywords for future use, so we name this
* function "extends" with capital E. Javascript is case-sensitive.
*
* @param function parent constructor function
* @param function (optional) used to override default child constructor function
*/
function Extends(parent, childConstructor) {
var F = function () {};
F.prototype = parent.prototype;
var Child = childConstructor || function () {};
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.parent = parent.prototype;
// return instance of new object
return Child;
}
/**
* Abstract Pizza object constructor
*/
function Pizza() {
throw new Error('Cannot instatiate abstract object!');
}
Pizza.prototype.price = 0;
Pizza.prototype.getPrice = function () {
return this.price;
}
var HamAndMushroomPizza = Extends(Pizza);
HamAndMushroomPizza.prototype.price = 8.5;
var DeluxePizza = Extends(Pizza);
DeluxePizza.prototype.price = 10.5;
var HawaiianPizza = Extends(Pizza);
HawaiianPizza.prototype.price = 11.5;
var PizzaFactory = {
createPizza: function (type) {
var baseObject = 'Pizza';
var targetObject = type.charAt(0).toUpperCase() + type.substr(1);
if (typeof window[targetObject + baseObject] === 'function') {
return new window[targetObject + baseObject];
}
else {
throw new Error('The pizza type ' + type + ' is not recognized.');
}
}
};
//var price = PizzaFactory.createPizza('deluxe').getPrice();
var pizzas = ['HamAndMushroom', 'Deluxe', 'Hawaiian'];
for (var i in pizzas) {
console.log('Price of ' + pizzas[i] + ' is ' + PizzaFactory.createPizza(pizzas[i]).getPrice());
}
Output
Price of HamAndMushroom is 8.50 Price of Deluxe is 10.50 Price of Hawaiian is 11.50
class Pizza a where
price :: a -> Float
data HamMushroom = HamMushroom
data Deluxe = Deluxe
data Hawaiian = Hawaiian
instance Pizza HamMushroom where
price _ = 8.50
instance Pizza Deluxe where
price _ = 10.50
instance Pizza Hawaiian where
price _ = 11.50
Usage example:
main = print (price Hawaiian)
package Pizza;
use Moose;
has price => (is => "rw", isa => "Num", builder => "_build_price" );
package HamAndMushroomPizza;
use Moose; extends "Pizza";
sub _build_price { 8.5 }
package DeluxePizza;
use Moose; extends "Pizza";
sub _build_price { 10.5 }
package HawaiianPizza;
use Moose; extends "Pizza";
sub _build_price { 11.5 }
package PizzaFactory;
sub create {
my ( $self, $type ) = @_;
return ($type . "Pizza")->new;
}
package main;
for my $type ( qw( HamAndMushroom Deluxe Hawaiian ) ) {
printf "Price of %s is %.2f\n", $type, PizzaFactory->create( $type )->price;
}
Factories are not really needed for this example in Perl, and this may be written more concisely:
package Pizza;
use Moose;
has price => (is => "rw", isa => "Num", builder => "_build_price" );
package HamAndMushroomPizza;
use Moose; extends "Pizza";
sub _build_price { 8.5 }
package DeluxePizza;
use Moose; extends "Pizza";
sub _build_price { 10.5 }
package HawaiianPizza;
use Moose; extends "Pizza";
sub _build_price { 11.5 }
package main;
for my $type ( qw( HamAndMushroom Deluxe Hawaiian ) ) {
printf "Price of %s is %.2f\n", $type, ($type . "Pizza")->new->price;
}
Output
Price of HamAndMushroom is 8.50 Price of Deluxe is 10.50 Price of Hawaiian is 11.50
<?php
abstract class Pizza
{
protected $_price;
public function getPrice()
{
return $this->_price;
}
}
class HamAndMushroomPizza extends Pizza
{
protected $_price = 8.5;
}
class DeluxePizza extends Pizza
{
protected $_price = 10.5;
}
class HawaiianPizza extends Pizza
{
protected $_price = 11.5;
}
class PizzaFactory
{
public static function createPizza($type)
{
$baseClass = 'Pizza';
$targetClass = ucfirst($type).$baseClass;
if (class_exists($targetClass) && is_subclass_of($targetClass, $baseClass))
return new $targetClass;
else
throw new Exception("The pizza type '$type' is not recognized.");
}
}
$pizzas = array('HamAndMushroom','Deluxe','Hawaiian');
foreach($pizzas as $p) {
printf(
"Price of %s is %01.2f".PHP_EOL ,
$p ,
PizzaFactory::createPizza($p)->getPrice()
);
}
// Output:
// Price of HamAndMushroom is 8.50
// Price of Deluxe is 10.50
// Price of Hawaiian is 11.50
?>
#
# Pizza
#
class Pizza(object):
def __init__(self):
self._price = None
def get_price(self):
return self._price
class HamAndMushroomPizza(Pizza):
def __init__(self):
self._price = 8.5
class DeluxePizza(Pizza):
def __init__(self):
self._price = 10.5
class HawaiianPizza(Pizza):
def __init__(self):
self._price = 11.5
#
# PizzaFactory
#
class PizzaFactory(object):
@staticmethod
def create_pizza(pizza_type):
if pizza_type == 'HamMushroom':
return HamAndMushroomPizza()
elif pizza_type == 'Deluxe':
return DeluxePizza()
elif pizza_type == 'Hawaiian':
return HawaiianPizza()
if __name__ == '__main__':
for pizza_type in ('HamMushroom', 'Deluxe', 'Hawaiian'):
print 'Price of {0} is {1}'.format(pizza_type, PizzaFactory.create_pizza(pizza_type).get_price())
As in Perl, Common Lisp and other dynamic languages, factories of the above sort aren't really necessary, since classes are first-class objects and can be passed around directly, leading to this more natural version:
#
# Pizza
#
class Pizza(object):
def __init__(self):
self._price = None
def get_price(self):
return self._price
class HamAndMushroomPizza(Pizza):
def __init__(self):
self._price = 8.5
class DeluxePizza(Pizza):
def __init__(self):
self._price = 10.5
class HawaiianPizza(Pizza):
def __init__(self):
self._price = 11.5
if __name__ == '__main__':
for pizza_class in (HamAndMushroomPizza, DeluxePizza, HawaiianPizza):
print('Price of {0} is {1}'.format(pizza_class.__name__, pizza_class().get_price()))
Note in the above that the classes themselves are simply used as values, which pizza_class iterates over. The class gets created simply by treating it as a function. In this case, if pizza_class holds a class, then pizza_class() creates a new object of that class. Another way of writing the final clause, which sticks more closely to the original example and uses strings instead of class objects, is as follows:
if __name__ == '__main__':
for pizza_type in ('HamAndMushroom', 'Deluxe', 'Hawaiian'):
print 'Price of {0} is {1}'.format(pizza_type, eval(pizza_type + 'Pizza')().get_price())
In this case, the correct class name is constructed as a string by adding 'Pizza', and eval is called to turn it into a class object.
Imports System
Namespace FactoryMethodPattern
Public Class Program
Shared Sub Main()
OutputPizzaFactory(New LousPizzaStore())
OutputPizzaFactory(New TonysPizzaStore())
Console.ReadKey()
End Sub
Private Shared Sub OutputPizzaFactory(ByVal factory As IPizzaFactory)
Console.WriteLine("Welcome to {0}", factory.Name)
For Each p As Pizza In factory.CreatePizzas
Console.WriteLine(" {0} - ${1} - {2}", p.GetType().Name, p.Price, p.Toppings)
Next
End Sub
End Class
Public MustInherit Class Pizza
Protected _toppings As String
Protected _price As Decimal
Public ReadOnly Property Toppings() As String
Get
Return _toppings
End Get
End Property
Public ReadOnly Property Price() As Decimal
Get
Return _price
End Get
End Property
Public Sub New(ByVal __price As Decimal)
_price = __price
End Sub
End Class
Public Interface IPizzaFactory
ReadOnly Property Name() As String
Function CreatePizzas() As Pizza()
End Interface
Public Class Pepperoni
Inherits Pizza
Public Sub New(ByVal price As Decimal)
MyBase.New(price)
_toppings = "Cheese, Pepperoni"
End Sub
End Class
Public Class Cheese
Inherits Pizza
Public Sub New(ByVal price As Decimal)
MyBase.New(price)
_toppings = "Cheese"
End Sub
End Class
Public Class LousSpecial
Inherits Pizza
Public Sub New(ByVal price As Decimal)
MyBase.New(price)
_toppings = "Cheese, Pepperoni, Ham, Lou's Special Sauce"
End Sub
End Class
Public Class TonysSpecial
Inherits Pizza
Public Sub New(ByVal price As Decimal)
MyBase.New(price)
_toppings = "Cheese, Bacon, Tomatoes, Tony's Special Sauce"
End Sub
End Class
Public Class LousPizzaStore
Implements IPizzaFactory
Public Function CreatePizzas() As Pizza() Implements IPizzaFactory.CreatePizzas
Return New Pizza() {New Pepperoni(6.99D), New Cheese(5.99D), New LousSpecial(7.99D)}
End Function
Public ReadOnly Property Name() As String Implements IPizzaFactory.Name
Get
Return "Lou's Pizza Store"
End Get
End Property
End Class
Public Class TonysPizzaStore
Implements IPizzaFactory
Public Function CreatePizzas() As Pizza() Implements IPizzaFactory.CreatePizzas
Return New Pizza() {New Pepperoni(6.5D), New Cheese(5.5D), New TonysSpecial(7.5D)}
End Function
Public ReadOnly Property Name() As String Implements IPizzaFactory.Name
Get
Return "Tony's Pizza Store"
End Get
End Property
End Class
End Namespace
Output:
Welcome to Lou's Pizza Store
Pepperoni - $6.99 - Cheese, Pepperoni
Cheese - $5.99 - Cheese
LousSpecial - $7.99 - Cheese, Pepperoni, Ham, Lou's Special Sauce
Welcome to Tony's Pizza Store
Pepperoni - $6.5 - Cheese, Pepperoni
Cheese - $5.5 - Cheese
TonysSpecial - $7.5 - Cheese, Bacon, Tomatoes, Tony's Special Sauce