Monday, February 14, 2011

Factory Pattern

Problem
I had a situation where I had to instantiate a class based on the condition, so I used if else if statements and was done with it, but after some time I had to add another condition to it, I had to go back and look for that code. What Should I do that in future I don't have to go through this process again.

Impact 
Code was hard to debug, and was less scalable.

Solution
I have alway been fascinated by Design patterns since I found out about them, but they are not easy to understand. There is a lot of material on the web about design patterns but I could't get my head around them, Most of the material that I found was too advance for my level so I start reading books, and believe me books are not that easy either. I found Headfirst design pattern, which seemed much better book than the other books, and in there I found the solution to my problem. Factory pattern. So when we have a situation where we need to instantiate a class based on a situation we should use factory pattern. Advantage of using factory pattern is that we know where to when we need to add another condition, plus we don't make any changes to our logic, all we have to do is ask the factory to create a class based on the situation.

IProduct  product  = ProductFactory.Create("Gucci Bag");

and factory should return the product.

I am going to create simple example so we could understand it better.

We understand the problem now and this is how we deal with it.
first of all alway try to work with the interface rather than concrete class. Coding to an interface is always better, you don't expose the whole class, only those parts that were implemented  by the interface.

public interface IProduct
    {
        string Name { get; set; }
    }

Now that we have an interface, we implement it to our classes.
Make sure the constructor of the class in always internal, otherwise client is free to instantiate concrete class then using factory.

    public class CalvinKlein:IProduct
    {
        public string Name { get; set; }

        internal CalvinKlein(string name)
        {
            Name = name;
        }

        public override string ToString()
        {
            return string.Format(Name);
        }
    }

public class GucciBag : IProduct
    {
        public string Name { get; set; }

        internal GucciBag(string name)
        {
            Name = name;
        }

        public override string ToString()
        {
            return Name;
        }
    }


In our store class we want to use our factory class to create our product, factory will produce item based on the product type that we are passing to the factory.

    public class Store
    {
        private IProduct _product;
        private IProductFactory _factory;

        public IProduct Buy(ProductType productType)
        {
            _factory = new ProductFactory();
            _product = _factory.Create(productType);
            return _product;
        }
    }

    public enum ProductType
    {
        GucciBag,
        CalvinKlein
    }

We use factory that will create the item for you. How does it work you say, well here first we create an interface name IFactory which contains one method called Create() that take one argument and return IProduct type. Now the argument that it takes will be enum type, and based on that type we will create our object. so here we go.

public interface IProductFactory
{
     IProduct Create(ProductType productType);
}

    public class ProductFactory:IProductFactory
    {
        private IProduct _product;

        public IProduct Create(ProductType productType)
        {
            if(ProductType.CalvinKlein == productType)
            {
                _product = new CalvinKlein("Calvin Klein");
            }
            else if(ProductType.GucciBag==productType)
            {
                _product = new GucciBag("Gucci Bag");
            }
            return _product;
        }
    }


Now finally we will use Main method to buy the items from the store and then display the name of the item we bought.

class Program
    {
        static void Main(string[] args)
        {
            Store myStore = new Store();
            IProduct product;
            product = myStore.Buy(ProductType.GucciBag);
            
            Console.WriteLine(product); // this will show we bought Gucci bag.
            product = myStore.Buy(ProductType.CalvinKlein);
            Console.WriteLine(product); // this will show that we bought Calvin klein product.
            Console.ReadLine();
        }
    }

1 comment: