factory method design pattern

Alcott picture Alcott · Sep 19, 2011 · Viewed 7.2k times · Source

According to the book:

The essence of the Factory Pattern is to "Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses.

Say I have a Creator class:

class Product; //this is what the Factory Method should return
class Creator {
    public:
        Creator()   //ctor
        { //... }

        virtual Product make(//args)
        { //... }
}

Ok, that's my Creator class, but I don't understand

The Factory method lets a class defer instantiation to subclasses

What does it have to do with subclasses? And what am I supposed to use subclasses for?

Anyone can give me some example?

Answer

Jorge Ferreira picture Jorge Ferreira · Sep 19, 2011

Your Creator class is the factory. Let's call it ProductFactory, in order to make the example more explicit.

(i am assuming you are using C++)

class Book : public Product
{
};

class Computer : public Product
{
};

class ProductFactory
{
public:
  virtual Product* Make(int type)
  {
    switch (type)
    {
      case 0:
        return new Book();
      case 1:
        return new Computer();
        [...]
    }
  }
}

Call it like this:

ProductFactory factory = ....;
Product* p1 = factory.Make(0); // p1 is a Book*
Product* p2 = factory.Make(1); // p2 is a Computer*
// remember to delete p1 and p2

So, to answer your question:

What does it have to do with subclasses? And what am I supposed to use subclasses for?

What the definition for factory pattern is saying is that the factory defines a common API for creating instances of a certain type (normally an interface or abstract class), but the real type of the implementations returned (thus the subclass reference) is the responsibility of the factory. In the example, the factory returns Product instances, for which Book and Computer are valid subclasses.

There are other idioms for factory, like having an API for the factory and the concrete implementations of the factory do not accept a type like in my example, but they are coupled with the type of instances returned, like this:

class ProductFactory
{
public:
  virtual Product* Make() = 0;
}

class BookProductFactory : public ProductFactory
{
public:
    virtual Product* Make()
    {
      return new Book();
    }
}

In this class BookProductFactory always returns Book instances.

ProductFactory* factory = new BookProductFactory();
Product* p1 = factory->Make(); // p1 is a Book
delete p1;
delete factory;

To make it clear, since there seems to be a bit of confusion between Abstract Factory and Factory method design patterns, let's see a concrete example:

Using Abstract Factory

class ProductFactory {
protected:
  virtual Product* MakeBook() = 0;
  virtual Product* MakeComputer() = 0;
}

class Store {
public:
   Gift* MakeGift(ProductFactory* factory) {
     Product* p1 = factory->MakeBook();
     Product* p2 = factory->MakeComputer();
     return new Gift(p1, p2);
   }
}

class StoreProductFactory : public ProductFactory {
protected:
  virtual Product* MakeBook() { return new Book(); }
  virtual Product* MakeComputer() { return new Computer(); }
}

class FreeBooksStoreProductFactory : public StoreProductFactory {
protected:
  virtual Product* MakeBook() {
    Book* b = new FreeBook(); // a FreeBook is a Book with price 0
    return b;
  }
}

That is used like this:

Store store;
ProductFactory* factory = new FreeBooksStoreProductFactory();
Gift* gift = factory->MakeGift(factory);
// gift has a FreeBook (Book with price 0) and a Computer
delete gift;
delete factory;

Using Factory method

class Store {
public:
   Gift* MakeGift() {
     Product* p1 = MakeBook();
     Product* p2 = MakeComputer();
     return new Gift(p1, p2);
   }

 protected:
   virtual Product* MakeBook() {
     return new Book();
   }

   virtual Product* MakeComputer() {
     return new Computer();
   }
}

class FreeBooksStore : public Store {
protected:
  virtual Product* MakeBook() {
    Book* b = new FreeBook(); // a FreeBook is a Book with price 0
    return b;
  }
}

That is used like this:

Store* store = new FreeBooksStore();
Gift* gift = store->MakeGift();
// gift has a FreeBook (Book with price 0) and a Computer
delete gift;
delete store;

When you use a type discriminator like I did in the original example, we are using parametized factory methods - a method that knows how to create different kind of objects. But that can appear in either an Abstract Factory or Factory Method pattern. A brief trick: if you are extending the factory class you are using Abstract Factory. If you extending the class with the creation methods, then you are using Factory Methods.