Factory Method
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.
Applicability
Use the Factory Method pattern when
- a class can't anticipate the class of objects it must create.
- a class wants its subclasses 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
Implementation
1. One Implementation With Java
UML diagram:
Source:
package design_patterns;
public class Test {
/** * @param args */ public static void main(String[] args) { testFactoryMethod(); }
private static void testFactoryMethod(){ AbstractCreator creator = new SubCreator1(); AbstractProduct prod = creator.makeProduct(); System.out.println(prod.getDescription());
creator = new SubCreator2(); prod = creator.makeProduct(); System.out.println(prod.getDescription()); } }
public abstract class AbstractCreator {
protected AbstractProduct makeProduct(){ return new ConcreteProduct1("Product1"); } } public class SubCreator1 extends AbstractCreator {
@Override protected AbstractProduct makeProduct() { return super.makeProduct(); }
} public class SubCreator2 extends AbstractCreator {
@Override protected AbstractProduct makeProduct() { return new ConcreteProduct2("Product2"); } }
public abstract class AbstractProduct { private String name; public AbstractProduct(String name){ this.name = name; }
public String getName() { return name; }
protected abstract String getDescription(); } public class ConcreteProduct1 extends AbstractProduct {
public ConcreteProduct1(String name) { super(name); }
@Override protected String getDescription() { StringBuffer sb = new StringBuffer(); sb.append("This is"); sb.append(this.getName()); return sb.toString(); } } public class ConcreteProduct2 extends AbstractProduct {
public ConcreteProduct2(String name) { super(name); }
@Override protected String getDescription() { return "This is ConcreteProduct2"; }
}
|
2. Another Implementation With C++
UML diagram:
Source:
#include "stdafx.h" #include "FactoryMethod.h" using namespace FactoryMethod;
template<class T> T MakeProductor(const char* name){ return T(name); }
int _tmain(int argc, _TCHAR* argv[]) { AbstractProduct *p ; ConcreteProduct1 c1 = MakeProductor<ConcreteProduct1>("ConcreteProduct1"); p = &c1; std::cout << p->getDescription() << std::endl; ConcreteProduct2 c2 = MakeProductor<ConcreteProduct2>(" ConcreteProduct2"); p = &c2; std::cout << p->getDescription() << std::endl; p = NULL;
return 0; }
-------------------------FactoryMethod.h--------------------------------------- #ifndef FACTORY_METHOD_H #define FACTORY_METHOD_H
#include "stdafx.h"
namespace FactoryMethod{
class AbstractProduct{
private: //const char* name; char* name;
//not allowed copy, because of const char* name and abstract class. //AbstractProduct(const AbstractProduct&) {}
void initName(const char* sName){ if(sName){ name = new char[strlen(sName) + 1]; strcpy(name, sName); } else{ name = new char[1]; *name = '/0'; } }
protected: char* description;
public: AbstractProduct(){ initName(NULL); description = (char*)malloc(sizeof(char) * 128);
sprintf(description,"%s","AbstractProduct(Default) has been constructed"); printf("%s/n", description); } //AbstractProduct(const char* name):name(name){} AbstractProduct(const char* name){ initName(name); description = (char*)malloc(sizeof(char) * 128); sprintf(description,"%s","AbstractProduct(WithName) has been constructed"); printf("%s/n", description); }
//if not define with virtual destructor, and if base pointer that points to a derived object, //then we delete the base pointer, the base class's destructor with be excuted, but the derived // object will not be excuted. So, To ensure that the proper destructor is run, // the destructor must be virtual in the base class.
//Like other virtual functions, the virtual nature of the destructor is inherited. //Therefore, if the destructor in the root class of the hierarchy is virtual, //then the derived destructors will be virtual as well. A derived destructor will be virtual //whether the class explicitly defines its destructor or uses the synthesized destructor.
virtual ~AbstractProduct(){ std::cout << "AbstractProduct has been destructed" << std::endl; if (description != NULL){ free(description); description = NULL; } if (name != NULL){ delete(name); name = NULL; } }
//AbstractProduct(const AbstractProduct& copy):name(copy.name),description(copy.description) {} AbstractProduct(const AbstractProduct& copy){ std::cout << "AbstractProduct(Copy) has been constructed" << std::endl; initName(copy.name); description = (char*)malloc(sizeof(char) * 128); strcpy(description,copy.description) ; }
//In VS8, it seems thas this method never be excuted. With assignment operator(=), it will always //excute the copy constructor to assign object whether the copy construtor is been explicitly defined or not. AbstractProduct &operator=(const AbstractProduct &prod){ std::cout << "operator= has been excuted" << std::endl; if(this != &prod){ initName(prod.name); strcpy(this->description,prod.description); } return *this; }
virtual const char* getDescription() const = 0;
const char* getName() const{ return name; }
};
class ConcreteProduct1: public AbstractProduct{
private: double price;
public: ConcreteProduct1(){ std::cout << "ConcreteProduct1(Default) has been constructed" << std::endl; };
ConcreteProduct1(const char* name):AbstractProduct(name),price(0.0){ std::cout << getName() << "(WithName) has been constructed" << std::endl; };
ConcreteProduct1(const char* name, double price):AbstractProduct(name),price(price){ std::cout << getName() << "(WithName&Price) has been constructed" << std::endl; };
~ConcreteProduct1(){ std::cout << getName() << " has been destructed" << std::endl; };
virtual const char* getDescription() const; };
class ConcreteProduct2: public AbstractProduct{ public: ConcreteProduct2(){ std::cout << "ConcreteProduct2(Default) has been constructed" << std::endl; };
ConcreteProduct2(const char* name):AbstractProduct(name){ std::cout << getName() << "(WithName) has been constructed" << std::endl; };
~ConcreteProduct2(){ std::cout << getName() << " has been destructed" << std::endl; };
/* Use the synthesized copy constructor and assignment operator */ //ConcreteProduct2(const ConcreteProduct2& copy):AbstractProduct(copy) {}
//ConcreteProduct2 &operator=(const ConcreteProduct2 &prod){ // AbstractProduct::operator=(prod); // return *this; //}
virtual const char* getDescription() const;
};
}
#endif FACTORY_METHOD_H
-------------------------FactoryMethod.cpp--------------------------------------- #include "stdafx.h" #include "FactoryMethod.h"
namespace FactoryMethod{
const char* ConcreteProduct1::getDescription() const{ memset(description,'/0',128); sprintf(description, "%s%s%f", getName(), "'s Price($) : ",price); return description; }
const char* ConcreteProduct2::getDescription() const{ memset(description,'/0',128); sprintf(description, "%s%s", "Welcome, this is ", getName()); return description; } } |
In above, I used the function template to create the concrete product. You can also use a singleton class to do the same thing. I will write the class when learn the Singleton pattern.
Usage example
The Connection object in the java package sql is a factory.
Depending on the database driver you use you get the database vendors. implementation of the Statement interface. In the following example we actually get an OracleStatement object from the package oracle.jdbc.driver when calling createStatement.
References:
1. Design Patterns - Elements of Reusable Object-Oriented Software, Gof
2. GoF Design Patterns with examples using Java and UML2