Monday, October 27, 2008

Factory Method Pattern(C#)

The Factory Method Pattern is an Object-Oriented design pattern, which deals with the problem of creating objects(products) without specifying the exact class of object that will be created. The Factory Method design pattern handles this problem by defining a separate method for creating the objects, whose subclasses can then override to specify the derived type of products 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.
Definition:
The essence of Factory Method is to "Define a interface for creating an object, but let the subclasses decide which class to instantiate. The Factory Method lets a class defer instantiation to subclasses."
Common Usage:
* Factory Method are common in toolkits and frameworks where library code need to create objects of types which may be subclassed by application using the framework.
* Parallel class hierarchies often require objects from one hierarchy to be able to create appropriate objects from another.
Limitations:
* The first limitation is that refactoring 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 earlier). But since the constructor is now private, the existing client code no longer compiles.
* The second limitation is that, 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.
* The third limitation is that, 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 with exactly the same signatures. 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.

All three problems could be alleviated by altering the underlying programming language to make factories first-class class members (rather than using the design pattern).

Example Code:

namespace FactoryMethod
{
public abstract class Pizza
{
public abstract decimal GetPrice();
public enum PizzaType
{
HamMushroom,Deluxe,Seafood
}

public static Pizza PizzaFactory(PizzaType pizzaType)
{
switch (pizzaType)
{
case PizzaType.HamMushroom:
return new HamAndMushroomPizza();
case PizzaType.Deluxe:
return new DeluxePizza();
case PizzaType.Seafood:
return new SeafoodPizza();
}

throw new System.NotSupportedException("The pizza type "+pizzaType.ToString()+" is not recognized.");
}
}

public class HamAndMushroomPizza : Pizza
{
private decimal Price = 8.5M;
public override decimal GetPrice()
{
return Price;
}
}

public class DeluxePizza : Pizza
{
private decimal Price = 10.5M;
public override decimal GetPrice()
{
return Price;
}
}

public class SeafoodPizza : Pizza
{
private decimal Price = 11.5M;
public override decimal GetPrice()
{
return Price;
}
}

class Program
{
static void Main(string[] args)
{
//output 11.50
Console.WriteLine(Pizza.PizzaFactory(Pizza.PizzaType.Seafood).GetPrice().ToString("C2"));
}
}
}