August 11, 2003

Creation Pattern - Factory Method

A factory object that is responsible for producing instances of other objects.

– Deals with the problem of creating objects (products) without specifying the exact class of object that will be created.

– The client requests a particular type of object from the factory, and the factory decides what object to instantiate.

– By defining a separate method for creating the objects, which subclasses can then override to specify the derived type of product that will be created. More generally, the term factory method is often used to refer to any method whose main purpose is creation of objects.

– The advantage of this pattern is that the client is oblivious of the actual object created; as long as the object adheres to the client's requirements (this is usually based on supported interfaces), the client never needs to know intricate details of the object.

– The Factory has intelligence

  • “Define an interface for creating an object, but let subclasses decide which class to instantiate”

– COM used this model: IClassFactory

Limitations

  • Re-factoring an existing class to use factories breaks existing clients. For example, if class Complex was a standard class, it might have numerous clients with code like:

Complex c = new Complex(-1, 0);

  • Once we realize that two different factories are needed, we change the class (to the code shown above). But since the constructor is now private, the existing client code no longer compiles.
  • Since the pattern relies on using a private constructor, the class cannot be extended. Any subclass must invoke the inherited constructor, but this cannot be done if that constructor is private.

If we do extend the class (e.g., by making the constructor protected -- this is risky but possible), the subclass must provide its own re-implementation of all factory methods, and with the exact same signature. For example, if class StrangeComplex extends Complex, then unless StrangeComplex provides its own version of all factory methods, the call StrangeComplex.fromPolar(1, pi) will yield an instance of Complex (the superclass) rather than the expected instance of the subclass.

Example:

Usually the Object is created as:

Stock stockT = new Stock();

The constructor of Stock initlizes stock data and can be hold within other class as:

Hold stock in Portfolio:

public class Portfolio {

private Stock[] stocks;

public Portfolio() { }

}

However it may create problems if:

– The constructor may change.

– Subclasses might appear in the future.

If we use Factory Method then -

Stock stockT = Portfolio.CreateStock();

– Now if the constructor changes, the change is in one function

– As long as the caller receives a Stock interface, it doesn’t care if it is a base class or a subclass.


namespace Patterns {
public interface IProduct {
string GetProductName();
}

public class ProductA : IProduct {
public string GetProductName() {
return "ProductA";
}
}

public class ProductB : IProduct {
public string GetProductName() {
return "ProductB";
}
}

// Creates & returns factory depending on id
public class Creator {
public static IProduct GetProductFactory(int id) {
if (id < 5)
return new ProductA();
else
return new ProductB();
}
}

// Client
public class FactoryCaller {
IProduct product;
public void CallFactory() {
product = Creator.GetProductFactory(1);
Console.WriteLine(product.GetProductName());
product = Creator.GetProductFactory(10);
Console.WriteLine(product.GetProductName());
}
}
}

Links: