Factory Method

Problem

A framework needs to standardize the architectural model for a range of applications, but allow for individual applications to define their own domain objects and abstract their instantiation.

The need to eliminate coupling between application-specific classes into the code.

Intent

- Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

- Defining a “virtual” constructor.

- The new operator considered harmful.

Applicability

- a class can't anticipate the class of objects it must create.

- a class wants its subclass to specify the objects it creates.

- classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.

Structure

Participants

- MyClass

defines the interface of objects the factory method creates.

- ConcreteMyClass

implements the MyClass interface

- Creator

declares the factory method, which returns an object of type MyClass. Creator may also define a default implementation of the factory method that returns a default ConcreteMyClass object.

- ConcreteCreator

overrides the factory method to return an instance of a ConcreteMyClass.

Thumb Rules

- A potencial disadvantage of factory methods is that clients might have to subclass the Creator class just to create a particular ConcreteMyClass object. Subclassing is fine when the client has to subclass the Creator class anyway, but otherwise the client now must deal with another point of evolution.

- Provides hooks for subclasses. Factory Method gives subclasses a hook for providing an extended version of an object.

- Two major varieties. The case when the Creator class is an abstract class and does not provide an implementation for the factory methods it declares. The subclass requires to define an implementation.

The case when the Creator is a concrete class and provides a default implementation for the factory method.

- Parameterized methods

class Creator

{

public:

virtual MyClass* CreateMyClass(MyClassId);

}

MyClass* Creator::CreateMyClass(MyClassId id)

{

if(id == MYCLASS_A) return new MyClassA();

if(id == MYCLASS_B) return new MyClassB();

if(id == MYCLASS_C) return new MyClassC();

return NULL;

}

Overriding a parameterized factory method lets you easily and selectively extend or change the products that a Creator produces.

MyClass* MyCreator::CreateMyClass(MyClassId id)

{

if(id == MYCLASS_A) return new MyClassB();

if(id == MYCLASS_B) return new MyClassA(); // swap the creation

if(id == MYCLASS_D) return new MyClassD();

return Creator::CreateMyClass(id); // parent called if others fail, work for MYCLASS_C

}

- Factory methods in C++ are always virtual functions and are often pure virtual. Just be careful not to call factory methods in the Creator's constructor, the factory method in the ConcreteCreator won't be available yet.

- Using templates to avoid subclassing

class Creator

{

public:

virtual MyClass* CreateMyClass() = 0;

}

template<class TheMyClass>

class MyCreator: public Creator

{

public:

virtual MyClass* CreateMyClass();

}

MyClass* MyCreator<TheMyClass>::CreateMyClass()

{

return new TheMyClass();

}

- Prototype doesn’t require subclassing, but it does require an Initialize operation. Factory Method requires subclassing, but doesn’t require Initialize.

- Factory Method is similar to Abstract Factory but without the emphasis on families.

- Factory Methods are usually called within Template Methods.

- Factory Method: creation through inheritance. Prototype: creation through delegation.

Code - Before

class MyClass

{

public:

virtual void print() = 0;

}

class MyClassA : public MyClass

{

public:

virtual void print()

{

std::cout << "\n" << "MyClassA";

}

}

class MyClassB : public MyClass

{

public:

virtual void print()

{

std::cout << "\n" << "MyClassB";

}

}

int main()

{

std::string type = "MyClassA";

MyClass *myClass;

if(0 == type.compare("MyClassA"))

myClass = new MyClassA();

else if(0 == type.compare("MyClassB"))

myClass = new MyClassB();

else

myClass = NULL;

if(myClass)

myClass->print();

}

MyClassA

Code - After

class MyClass

{

public:

virtual void print() = 0;

}

class MyClassA : public MyClass

{

public:

virtual void print()

{

std::cout << "\n" << "MyClassA";

}

}

class MyClassB : public MyClass

{

public:

virtual void print()

{

std::cout << "\n" << "MyClassB";

}

}

class Creator

{

public:

MyClass* CreateMyClass(std::string type) = 0;

};

class MyCreator

{

public:

MyClass* CreateMyClass(std::string type)

{

if(0 == type.compare("MyClassA"))

return new MyClassA();

else if(0 == type.compare("MyClassB"))

return new MyClassB();

else

return NULL;

}

};

int main()

{

std::string type = "MyClassA";

Creator myCreator = new MyCreator()

MyClass myClass = myCreator.CreateMyClass(type);

if(myClass)

myClass->print();

}

MyClassA