Thursday, October 16, 2008

Design Patterns (4) - Factory method and Abstract Factory

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

 

Why would anybody use such a design pattern?

Imagine you are writing the code for the “Client” object. The “client” object needs to use the “Product” object. You hard code the object creation process in the “Client” Now any changes in the object creation procedure would mean that you need to change the “client” too. The sole purpose of the “Factory” object is to create “Product” This gives us a certain amount of flexibility. The “client” delegates that task to “Factory”. Any changes in the object creation process do not affect the “client” and changes to “Factory” should be fairly simple as that is the only thing it does.

ref: http://vorleakchy.wordpress.com/2008/08/15/factory-method-design-pattern/

Principles:

No variable should hold a reference to  a concrete class. If you use new, you' ll be holding a reference to a concrete class. Use a factory to get around that!

No class should derive from a concrete class. If you derive from a concret class, you're depending on a concrete class. Derive from an abstraction, like an interface or an abstract class.

No method should override an implemented method of any its base class.  If you override an implemented method, then your base class wasn't really an abstraction to start with. Those methods implemented in the base class are meant to be shared by all your subclasses.image

My simple factory method example:

//Pizza example:

#include <string>
#include <iostream>
class Pizza {
public:
virtual void get_price() = 0;
};

class HamAndMushroomPizza: public Pizza {
public:
virtual void get_price(){
std::cout << "Ham and Mushroom: $8.5" << std::endl;
}
};

class DeluxePizza : public Pizza {
public:
virtual void get_price() {
std::cout << "Deluxe: $10.5" << std::endl;
}
};

class SeafoodPizza : public Pizza {
public:
virtual void get_price(){
std::cout << "Seafood: $11.5" << std::endl;
}
};

class PizzaFactory {
public:
static Pizza* create_pizza(const std::string type) {
if (type == "Ham and Mushroom")
return new HamAndMushroomPizza();
else if (type == "Seafood Pizza")
return new SeafoodPizza();
else
return new DeluxePizza();
}
};
//usage
int main() {
PizzaFactory factory;
Pizza *pz = factory.create_pizza("Default");
pz->get_price();

Pizza *ph = factory.create_pizza("Ham and Mushroom");
ph->get_price();

delete pz;
pz = factory.create_pizza("Seafood Pizza");

pz->get_price();
delete pz;
delete ph;
}