Thursday, January 15, 2009

Factory Pattern

After long I am blogging something on design pattern. When I started writing about design pattens, the idea was to make everyone understand patterns in simple and understandable form as I have seen many think Patterns are hard to imbibe. But after posting my first blog, singleton, I was not quite happy with the way it was written. There was nothing different. The usual stuff. So I went to an ideating mode where I was conceptualizing how to write in simple terms so that everyone can understand. I came across this book called "Head first Design patterns". I read the book and it was quite different from other books. Patterns explained using cartoons, pictures et all. I would recommend anyone who wants to learn design patterns to have a look at this book. I thought why not write something on those lines but drawing cartoons, images will be time consuming and I am not so great in drawing also. So I thought I will write my design pattern blog as a story and the hero of my story will be a Common Developer. This blog is the first in a series of blog which I am planning to write based on this idea. Hope it will be informative. In this blog we will take a look at Factory pattern from our hero' point of view. So we embark on our journey to learn design pattern with our Common Developer (CD).

The story starts when our Common developer gets a job as what else developer. He started earning money and over a period of time he decides to invest his money on a car. Since he is very fond of Hyundai brand of cars he decides to buy one. We know Hyundai has got different types of cars like the Santro, i10, i20, Accent, Sonata etc. To buy his dream car CD went to a Hyundai showroom and ordered the latest i10.

Our CD started thinking from a developer' point of view on how to implement this whole scenario into a Object Oriented (OO) software program. CD decided to reproduce the real life system in OO terms. To design the system CD decided to first design the classes for the various models of Hyundai car.

CD decided to make use of inheritance to design his car classes. He designed a base class called Car from which other types of cars like Santro, i10, i20 etc were extended. Why this approach? Our CD chose i10 as his choice of car but someone else can buy Sonata and to give extensibility CD made use of inheritance. For e.g. in future say Hyundai introduces some new model then CD may be easily able provide extensibility. The classes designed by CD is shown below.

clip_image002

So from the above diagram we can infer that we have a common base class called car which is an abstract class from which all the other classes are inherited. The reason why CD decided to keep the “Car” as abstract is that Car class by itself doesn’t serve any purpose, only when it gets an implementation in the form of concrete classes like Santro, i10 etc it has some existence. Ultimately everyone wants car and every model is a car but they have different attributes like different Cubic Capacity, Max Power, Max Torque etc. The C# code for the “Car” and other inherited classes is given below.

 

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    public abstract class Car
    {
        public abstract float CC
        {
            get;
        }
        public abstract float Length
        {
            get;
        }

        public abstract float Width
        {
            get;
        }

        public abstract float Height
        {
            get;
        }

        public abstract float GroundClearance
        {
            get;
        }

        public abstract float MaxPower
        {
            get;
        }

        public abstract float MaxTorque
        {
            get;
        }

        public abstract float MaxSpeed
        {
            get;
        }

        public abstract float TankCapacity
        {
            get;
        }

        public abstract bool StartCar();

        public string CarName
        {
            get
            {
                return this.GetType().Name;
            }
        }
    }
}

 

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class Santro : Car
    {
        private float m_cc;
        private float m_lenght;
        private float m_width;
        private float m_height;
        private float m_groundClearance;
        private float m_maxPower;
        private float m_maxTorque;
        private float m_maxSpeed;
        private float m_tankCapacity;

        public Santro()
        {
            this.m_cc = 1086;
            this.m_lenght = 3565;
            this.m_width = 1525;
            this.m_height = 1590;
            this.m_groundClearance = 172;
            this.m_maxPower = 63;
            this.m_maxTorque = 89;
            this.m_maxSpeed = 141;
            this.m_tankCapacity = 35;
        }

        public override float CC
        {
            get
            {
                return this.m_cc;
            }           
        }

        public override float Length
        {
            get
            {
                return this.m_lenght;
            }           
        }

        public override float Width
        {
            get
            {
                return this.m_width;
            }           
        }

        public override float Height
        {
            get
            {
                return m_height;
            }
        }

        public override float GroundClearance
        {
            get
            {
                return this.m_groundClearance;
            }
        }

        public override float MaxPower
        {
            get
            {
                return this.m_maxPower;
            }
        }

        public override float MaxTorque
        {
            get
            {
                return this.m_maxTorque;
            }
        }

        public override float MaxSpeed
        {
            get
            {
                return this.m_maxSpeed;
            }
        }

        public override float TankCapacity
        {
            get
            {
                return this.m_tankCapacity;
            }
        }

        public override bool StartCar()
        {
            Console.WriteLine(base.CarName + " started.");
            return true;
        }
    }
}

 

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class i10 : Car
    {
        private float m_cc;
        private float m_lenght;
        private float m_width;
        private float m_height;
        private float m_groundClearance;
        private float m_maxPower;
        private float m_maxTorque;
        private float m_maxSpeed;
        private float m_tankCapacity;

        public i10()
        {
            this.m_cc = 1086;
            this.m_lenght = 3565;
            this.m_width = 1595;
            this.m_height = 1550;
            this.m_groundClearance = 165;
            this.m_maxPower = 67;
            this.m_maxTorque = 99;
            this.m_tankCapacity = 35;
        }
        public override float CC
        {
            get
            {
                return this.m_cc;
            }
        }

        public override float Length
        {
            get
            {
                return this.m_lenght;
            }
        }

        public override float Width
        {
            get
            {
                return this.m_width;
            }
        }

        public override float Height
        {
            get
            {
                return m_height;
            }
        }

        public override float GroundClearance
        {
            get
            {
                return this.m_groundClearance;
            }
        }

        public override float MaxPower
        {
            get
            {
                return this.m_maxPower;
            }
        }

        public override float MaxTorque
        {
            get
            {
                return this.m_maxTorque;
            }
        }

        public override float MaxSpeed
        {
            get
            {
                return this.m_maxSpeed;
            }
        }

        public override float TankCapacity
        {
            get
            {
                return this.m_tankCapacity;
            }
        }

        public override bool StartCar()
        {
            Console.WriteLine(base.CarName + " started.");
            return true;
        }
    }
}

 

Now that CD has finished his base Car class design he decided to design the Hyundai factory which can create these cars. Here again CD can go with two approach that is he can have one factory for creating Hyundai cars or can go with different factories for different cars. CD decides to try both to understand them better.

CD decided to go with the first approach where he will have a single Hyundai factory to manufacture all the cars. In this approach CD created a Hyundai factory class with a method “CreateCar” which took string as an argument to create the choice of car CD wanted. Below is the code for the factory implementation.

 

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class HyundaiFactory
    {
        public Car CreateCar(string theCarType)
        {
            if (theCarType != null && theCarType != string.Empty)
            {
                if (theCarType.ToLower().Trim() == "santro")
                {
                    return new Santro();
                }
                else if (theCarType.ToLower().Trim() == "i10")
                {
                    return new i10();
                }
                else if (theCarType.ToLower().Trim() == "i20")
                {
                    return new i20();
                }
                else if (theCarType.ToLower().Trim() == "accent")
                {
                    return new Accent();
                }
                else if (theCarType.ToLower().Trim() == "sonata")
                {
                    return new Sonata();
                }              
            }

            return null;
        }
    }
}

You can see from the above class that we have a method called “CreateCar” which accepts a string as an argument and based on the argument the factory creates the car and returns the car of choice. Seeing the method signature we know why CD went ahead with the inheritance approach. He wanted the factory to be able to return any type of car and this is possible only through inheritance. Also car by itself doesn't have any existence unless it takes the form of Santro, i10, 120 etc. So the car class was declared abstract. CD was not happy with the current implementation, he wanted to make this approach more OO based , so he thought of changing the argument of the method to a class called “CarDescription”. The structure of the class is shown below.

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class CarDescription
    {
        private string m_carName;
        private bool m_powerWindow;
        private bool m_powerSteering;
        private bool m_centralLocking;
        private string m_color;

        public string CarName
        {
            get
            {
                return this.m_carName;
            }
            set
            {
                this.m_carName = value;
            }
        }

        public bool PowerWindow
        {
            get
            {
                return this.m_powerWindow;
            }
            set
            {
                this.m_powerWindow = value;
            }
        }

        public bool PowerSteering
        {
            get
            {
                return this.m_powerSteering;
            }
            set
            {
                this.m_powerSteering = value;
            }
        }

        public bool CentralLocking
        {
            get
            {
                return this.m_centralLocking;
            }
            set
            {
                this.m_centralLocking = value;
            }
        }

        public string Color
        {
            get
            {
                return this.m_color;
            }
            set
            {
                this.m_color = value;
            }
        }
    }
}

Now using the above class CD was able to fine tune the features and customise his requirement like which color he wanted, whether he wanted power window, power steering, central locking etc for his choice of car. Once he thought of implementing the above class the signature of the factory method needed a change, he had two option either change the existing function to something like the one below or he can overload the method in the Hyundai factory. Anyway whatever options CD chose the signature of the method will look something like this.

public Car a CreateCar(CarDescription theCarDescriptor)

While trying to implement the new change he was faced with new problem, like, now he need to build the car based on many criteria and which could be complex. After much research he came to know, that, to build complex objects like car based on various criteria he can implement builder pattern. He decided he can extend the application and make use of builder pattern later as he was not very clear on builder pattern and implement builder in later stages when he has a sound knowledge of builder. Next he decided to create the showroom for ordering the cars. The showroom class is shown below.

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class ShowRoom
    {
        static System.Collections.Hashtable hashTable = new
        System.Collections.Hashtable();
        static void Main(string[] args)
        {
            HyundaiFactory hyunFact = new HyundaiFactory();
            //Getting the car the user wants.
            Console.WriteLine("Allowed entries: Accent, i10, i20,
            Santro, Sonata");
            Console.WriteLine("Enter car you want to buy? ");
            string carType = Console.ReadLine();
            Car hyundaiCar = hyunFact.CreateCar(carType);
            //Displaying the car.
            Console.WriteLine("The car you ordered for: " +
            hyundaiCar.CarName);
            Console.WriteLine("Cubic Capacity: " +
            hyundaiCar.CC.ToString());
            Console.WriteLine("Max power: " +
            hyundaiCar.MaxPower.ToString());
            Console.WriteLine("Max torque: " +
            hyundaiCar.MaxTorque.ToString());
            Console.WriteLine("Fuel tank capacity: " +
            hyundaiCar.TankCapacity.ToString());
            Console.ReadLine();
        }
   }
}

So from the above code you can see how the car is created using the factory pattern using the first approach.

After completing the first option CD started implementing the second way of implementing the factory and wanted to see how it is different from the one he has already implemented.

In the second implementation of Factory, CD had to create a base factory called “HyundaiFactory”, from which his other car factories will be extended to create the individual car model factory. Below is the diagram depicting the class structure.

clip_image004

From the above diagram we can infer that CD has created a Base class called “HyundaiFactory” which is an abstract class. From this abstract factory all the other factories are inherited like the “HyundaiAccentFactory” (will create Accents cars), “Hyundaii10Factory” (will create i10 cars) etc. The code for the above class is shown below.

Abstract car factory code.

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    public abstract class HyundaiFactory
    {       
        public abstract Car CreateCar();       
    }
}

Accent car factory code.

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class HyundaiAccentFactory : HyundaiFactory
    {
        public override Car CreateCar()
        {
            return new Accent();
        }
    }
}

i10 car factory code.

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class Hyundaii10Factory : HyundaiFactory
    {
        public override Car CreateCar()
        {
            return new i10();
        }
    }
}

i20 car factory code.

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class Hyundaii20Factory : HyundaiFactory
    {
        public override Car CreateCar()
        {
            return new i20();
        }
    }
}

Santro car factory code

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class HyundaiSantroFactory : HyundaiFactory
    {
        public override Car CreateCar()
        {
            return new Santro();
        }
    }
}

Sonata car factory code

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class HyundaiSonataFactory : HyundaiFactory
    {
        public override Car CreateCar()
        {
            return new Sonata();
        }
    }
}

From the above code one can see that each factory returns the car of a particular type. After completing the ground work for the factory pattern, CD created the “ShowRoom” class where he can make use of the factory and order the car of his choice. The “ShowRoom” class code is shown below.

The second factory implementation is given below

using System;
using System.Collections.Generic;
using System.Text;

namespace Factory_Pattern
{
    class ShowRoom
    {
        static System.Collections.Hashtable hashTable = new
        System.Collections.Hashtable();
        static void Main(string[] args)
        {
            // Creating all the factories and adding to the hashtable.
            hashTable.Add("accent", new HyundaiAccentFactory());
            hashTable.Add("i10", new Hyundaii10Factory());
            hashTable.Add("i20", new Hyundaii20Factory());
            hashTable.Add("santro", new HyundaiSantroFactory());
            hashTable.Add("sonata", new HyundaiSonataFactory());

            //Getting the car the user wants.
            Console.WriteLine("Allowed entries: Accent, i10, i20,
            Santro, Sonata");
            Console.WriteLine("Enter car you want to buy? ");

            string carType = Console.ReadLine();
            //Retrieving the factory fromt the collection.
            HyundaiFactory hyunFact =
            (HyundaiFactory)hashTable[carType.ToLower().Trim()];
            //Creating the car of the user' choice from the respective
            //factory.
            Car hyundaiCar = hyunFact.CreateCar();
            //Making use of the car.
            Console.WriteLine("The car you ordered for: " +
            hyundaiCar.CarName);
            Console.WriteLine("Cubic Capacity: " +
            hyundaiCar.CC.ToString());
            Console.WriteLine("Max power: " +
            hyundaiCar.MaxPower.ToString());
            Console.WriteLine("Max torque: " +
            hyundaiCar.MaxTorque.ToString());
            Console.WriteLine("Fuel tank capacity: " +
            hyundaiCar.TankCapacity.ToString());
            Console.ReadLine();
        }
    }
}

Now after completing the above implementation CD thought of understanding further on the pattern. So he decided he should know the following like the original definition given by GOF, what problem this pattern solves?, how it solves the problem?, and real time implementation. So he decided to note down all this. Below his what CD noted in his notepad for reference.

Gof Definition:

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

What is the problem this pattern solves?

When I have a scenario where I don’t want the user to directly instantiate the class but want the class to be created based on some criteria I can implement factory and the factory will take the responsibility of creating the object based on some argument received by the factory method. Also you can implement factory when you don’t know what type of related object you want to create, only during run time you will know which object to create based on some input.

How it Solves the Problem?

To solve the problem one needs a set of related classes, in this case "Car", Santro, i10 etc. There will be a base class (Product) from which all the other classes (Concrete Product) will inherit and mostly the base class will be abstract or it will be in the form of an interface. The inherited class will have the concrete implementation of the base class. Then one should have a factory class to create the related classes or you can have a base factory (Creator) from which other factories (Concrete Creator) will inherit. So this is the basic requirement to have a factory.

Real time e.g.

In .NET factory is implemented in page life cycle where “PageHandlerFactory” is used to create an ASP.NET page handler dynamically to process ASP.NET page requests. Other factory implementation in .net are “WebServiceHandlerFactory”, “SimpleHandlerFactory”, “HttpRemotingHandlerFactory” to handle, webservice, simple handlers, remoting requests respectively. Also you can find the implementation of factory in WebRequest class’ Create method, AppDomain’ CreateDomain method et all.

So with this CD was clear on Factory pattern and I hope the same is case with the reader' of this blog.

Love patterns,

Sandeep

No comments:

Post a Comment

Leave your valuable comments here.