new
operator considered harmful.
Factory Method makes a design more customizable and only a little more complicated. Other design patterns require new classes, whereas Factory Method only requires a new operation. [GoF, p136]
People often use Factory Method as the standard way to create objects; but it isn't necessary if: the class that's instantiated never changes, or instantiation takes place in an operation that subclasses can easily override (such as an initialization operation). [GoF, p136]
Factory Method is similar to Abstract Factory but without the emphasis on families.
Factory Methods are routinely specified by an architectural framework, and then implemented by the user of the framework.
static
method of a class that returns an object
of that class' type. But unlike a constructor, the actual
object it returns might be an instance of a subclass. Unlike
a constructor, an existing object might be reused, instead of
a new object created. Unlike a constructor, factory methods
can have different and more descriptive names (e.g.
Color.make_RGB_color(float red, float green, float blue) and
Color.make_HSB_color(float hue, float saturation, float brightness).
[Davis, p3]
static
factory method in the base class.
private
or
protected
.
Before | After | |
---|---|---|
// The architect has done an admirable job of // decoupling the client from Stooge concrete // derived classes, and, exercising polymorphism. // But there remains coupling where instances are // actually created. If we design an "extra // level of indirection" (a "factory method") and // have clients use it (instead of "new"), then // the last bit of coupling goes away. The // "factory method" (aka "virtual constructor") // can be defined in the Stooge base class, or, // in a separate "factory" class. Note that // main() is no longer dependent on Stooge // derived classes. class Stooge { public: virtual void slap_stick() = 0; }; class Larry : public Stooge { public: void slap_stick() { cout << "Larry: poke eyes\n"; } }; class Moe : public Stooge { public: void slap_stick() { cout << "Moe: slap head\n"; } }; class Curly : public Stooge { public: void slap_stick() { cout << "Curly: suffer abuse\n"; } }; int main( void ) { vector<Stooge*> roles; int choice; while (true) { cout << "Larry(1) Moe(2) Curly(3) Go(0): "; cin >> choice; if (choice == 0) break; else if (choice == 1) roles.push_back( new Larry ); else if (choice == 2) roles.push_back( new Moe ); else roles.push_back( new Curly ); } for (int i=0; i < roles.size(); i++) roles[i]->slap_stick(); for (int i=0; i < roles.size(); i++) delete roles[i]; } // Larry(1) Moe(2) Curly(3) Go(0): 2 // Larry(1) Moe(2) Curly(3) Go(0): 1 // Larry(1) Moe(2) Curly(3) Go(0): 3 // Larry(1) Moe(2) Curly(3) Go(0): 0 // Moe: slap head // Larry: poke eyes // Curly: suffer abuse | // A factory method is a static method of a class that // returns an object of that class' type. But unlike a // constructor, the actual object it returns might be // an instance of a subclass. Another advantage of a // factory method is that it can return existing // instances multiple times. [Mark Davis] class Stooge { public: // Factory Method static Stooge* make_stooge( int choice ); virtual void slap_stick() = 0; }; int main( void ) { vector<Stooge*> roles; int choice; while (true) { cout << "Larry(1) Moe(2) Curly(3) Go(0): "; cin >> choice; if (choice == 0) break; roles.push_back( Stooge::make_stooge( choice ) ); } for (int i=0; i < roles.size(); i++) roles[i]->slap_stick(); for (int i=0; i < roles.size(); i++) delete roles[i]; } class Larry : public Stooge { public: void slap_stick() { cout << "Larry: poke eyes\n"; } }; class Moe : public Stooge { public: void slap_stick() { cout << "Moe: slap head\n"; } }; class Curly : public Stooge { public: void slap_stick() { cout << "Curly: suffer abuse\n"; } }; Stooge* Stooge::make_stooge( int choice ) { if (choice == 1) return new Larry; else if (choice == 2) return new Moe; else return new Curly; } |
Factory Methods are usually called within Template Methods. [GoF, p116]
Factory Method: creation through inheritance. Prototype: creation through delegation.
Often, designs start out using Factory Method (less complicated, more customizable, subclasses proliferate) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, more complex) as the designer discovers where more flexibility is needed. [GoF, p136]
Prototype doesn't require subclassing, but it does require an Initialize operation. Factory Method requires subclassing, but doesn't require Initialize. [GoF, p116]
The advantage of a Factory Method is that it can return the same instance multiple times, or can return a subclass rather than an object of that exact type. [Davis, p4]
Some Factory Method advocates recommend that as a matter of language design (or failing that, as a matter of style) absolutely all constructors should be private or protected. It's no one else's business whether a class manufactures a new object or recycles an old one. [Davis, p5]
The new
operator considered harmful. There is a difference
between requesting an object and creating one. The new
operator always creates an object, and fails to encapsulate
object creation. A Factory Method enforces that encapsulation,
and allows an object to be requested without inextricable
coupling to the act of creation. [Amsterdam, p19]