Sunday, March 8, 2009

Abstract factory

In the previous blog you would have seen Factory Pattern, this blog we will go along with Common Developer (CD) to have a look at what is Abstract Factory. After getting his dream car CD was happily driving it and showing it off to his friends and colleagues. Seeing CD’ car one of his colleague Another Common Developer (ACD) wanted to get a car for himself. But his requirement was different. He wanted to try different models and then select the best. ACD was not particular about a brand unlike CD who was very much particular about the brand Hyundai and also the model i10. ACD wanted to test drive different brand cars and then finalise on one or two and choose from among the short listed ones. ACD approached CD to get some tips on buying a car. After listening to ACD’ requirement CD suggested that he can approach a multi car brand showroom rather than a particular brands showroom. Taking CD’ advice ACD went to multi brand showroom and test drove many cars and finally settled for Toyota Camry. ACD called CD and informed him about his choice.

After finishing the call CD’ developer mind kicked in and started thinking how to implement ACD’ requirement in software terms. He has already implemented Factory pattern for solving his requirement where he was clear on which car he wanted and which brand he is looking for. After giving some thought CD noted down the following points.

  • There will be a set of different classes than the one in factory where everything was Hyundai brand of cars.

  • Different factories needed to create these different classes.

After doing a research CD found out that the best way to approach this scenario is to make use of the Abstract Factory pattern. There are many variations to the Abstract Factory and CD decided to try the two variations (Actually there is only one Abstract Factory proposed by the GOF. But over a period variations popped up. The second Abstract Factory pattern described in this blog is the one proposed by GOF.) Lets see the first variation. For the first implementation CD decided to build the building blocks of Abstract Factory. For this CD needed to create the products which the different factories can create. He thought of changing his Factory pattern implementation to incorporate Abstract Factory. The initial class created for factory pattern is listed below on which CD is planning to add new car models.

image

To incorporate Abstract Factory CD added new cars of different manufacturer. He added Ikon, Fiesta and Fusion models from Ford, Camry and Corrola models from Toyota and City, Civic and Accord models from Honda. The new class structure is show below.

image

From the above class diagram one can see that the new models are inheriting from the same Abstract Car class. The Initial product development is over. Now comes the factory creation. This implementation you can say is an extension of the first factory implementation method we saw in Factory pattern. In the first implementation of factory pattern we had only a concrete factory to create all the Hyundai cars. In the Abstract Factory implementation we will have base class from which all the car factories will inherit. The base class can be an abstract class or an interface. CD is making use of an interface called ICarFactory. The code is pasted below.

using System;
using System.Collections.Generic;
using System.Text;
using Factory_Pattern.Products;

namespace Factory_Pattern.Factory
{
    interface ICarFactory
    {
        Car CreateCar(string theCarName);
        string CarModelsAvailable{get;}
    }
}

The interface, ICarFactory, has got a method called “CreateCar” which takes the car name as the string argument and returns a “Car” object. All the car factories will inherit from this interface and implement their car manufacturing methods. The other method in the interface is “CarModelAvailable”. This method will return a string which will list out the models available with the brand. The sample code of “HyundaiCarFactory” and “ToyotaCarFactory” is given below.

using System;
using System.Collections.Generic;
using System.Text;
using Factory_Pattern.Products;

namespace Factory_Pattern.Factory
{
    class HyundaiCarFactory : ICarFactory
    {
        Car ICarFactory.CreateCar(string carName)
        {
            Car hyundaiCar = null;

            if (!string.IsNullOrEmpty(carName))
            {
                switch (carName.ToLower().Trim())
                {
                    case "santro":
                        hyundaiCar = new Santro();
                        break;
                    case "i10":
                        hyundaiCar = new i10();
                        break;
                    case "i20":
                        hyundaiCar = new i20();
                        break;
                    case "sonata":
                        hyundaiCar = new Sonata();
                        break;
                    default:
                        throw new Exception("No such Hyundai cars available in our kitty.");                       
                }               
            }

            return hyundaiCar;
        }

        string ICarFactory.CarModelsAvailable
        {
            get
            {
                return "Models available: Santro, i10, i20 and Sonata.";
            }
        }
    }
}

“ToyotaCarFactory” code.

using System;
using System.Collections.Generic;
using System.Text;
using Factory_Pattern.Products;

namespace Factory_Pattern.Factory
{
    class ToyotaCarFactory : ICarFactory
    {  
        Car ICarFactory.CreateCar(string carName)
        {
            Car toyotaCar = null;

            if (!string.IsNullOrEmpty(carName))
            {
                switch (carName.ToLower().Trim())
                {
                    case "camry":
                        toyotaCar = new Camry();
                        break;
                    case "corolla":
                        toyotaCar = new Corolla();
                        break;                  
                    default:
                        throw new Exception("No such Toyota model available in our kitty.");
                }
            }

            return toyotaCar;
        }

        string ICarFactory.CarModelsAvailable
        {
            get
            {
                return "Models available: Camry and Corolla.";
            }
        }
    }
}

As you can see both the factory codes are nothing great, they just check the string and return the appropriate car model. The class diagram for the factories is given below.

image

As you can see from the diagram all the car factories inherit from the same interface. Each one has its own implementation of the “CreateCar” method which does the work of creating the respective car models of the company. As the factories are ready CD needed a place to assemble the cars and deliver them to the customer. For assembling the car CD created a class called the “AssemblyFloor”. The code for the class is shown below.

using System;
using System.Collections.Generic;
using System.Text;
using Factory_Pattern.Factory;
using Factory_Pattern.Products;

namespace Factory_Pattern
{
    class AssemblyFloor
    {
        ICarFactory carFactory;

        AssemblyFloor(ICarFactory theCarFactory)
        {
            this.carFactory = theCarFactory;
        }

        public Car DeliverCar(string theCarName)
        {
            return carFactory.CreateCar(theCarName);
        }
    }
}

The “AssemblyFloor” takes an “ICarFactory” implemented object as an argument in its constructor and sets it to one of its member variable. The “DeliverCar” method takes the car name as a string and calls the appropriate method of the factory to create the car. With the assembly floor the requirement to implement Abstract Factory is completed. While doing a code walkthrough CD found out that he has nearly four factories for the different brands. To create the factories dynamically, CD came up with an idea to have a factory to create the dynamic factory. So he created a factory for factory. The code is shown below.

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

namespace Factory_Pattern.Factory
{
    class CarFactoryCreator
    {
        public static ICarFactory CreateCarFactory(string theFactoryName)
        {
            ICarFactory carFactory = null;

            if (!string.IsNullOrEmpty(theFactoryName))
            {
                switch (theFactoryName.ToLower().Trim())
                {
                    case "ford":
                        carFactory = new FordCarFactory();
                        break;
                    case "hyundai":
                        carFactory = new HyundaiCarFactory();
                        break;
                    case "toyota":
                        carFactory = new ToyotaCarFactory();
                        break;
                    case "honda":
                        carFactory = new HondaCarFactory();
                        break;
                    default:
                        throw new Exception("The requested factory is not available. Valid entries are Ford, Honda, Hyundai and Toyota.");                       
                }
            }

            return carFactory;
        }
    }
}

Please note a very important point, the above class is not a part of the Abstract Factory, it is just a helper factory class. The helper class will help to create the factories based on different user’ requirement. The factory and products to be created by the factory are in place. CD wrote a Showroom class to make use of all the classes and see the behavior of Abstract Factory. The code of Showroom class is pasted below.

using System;
using System.Collections.Generic;
using System.Text;
using Factory_Pattern.Factory;
using Factory_Pattern.Products;

namespace Factory_Pattern
{
    class ShowRoom
    {      
        static void Main(string[] args)
        {
            Console.WriteLine("Please provide your brand preference? " +
                "Allowed values: Ford, Honda, Hyundai and Toyota.");
            string brand = Console.ReadLine();
            ICarFactory carFactory = CarFactoryCreator.CreateCarFactory(brand);
            Console.WriteLine("Please provide the car you would like to " +
                "purchase from {0} brand? {1}", brand, carFactory.CarModelsAvailable);
            string carName = Console.ReadLine();
            AssemblyFloor assemblyFloor = new AssemblyFloor(carFactory);
            Car customerCar = assemblyFloor.DeliverCar(carName);
            Console.WriteLine("Your {0} car is ready to be delivered."
                , customerCar.CarName);
            Console.ReadLine();
        }
    }
}

With the above code the abstract factory implementation is pretty much done.

Next CD thought of implementing the second approach to Abstract factory (the original pattern proposed by GOF). The difference which CD noted between Abstract Factory first approach and the new approach which he is going to implement is that in the second approach the products don’t have a single base class like that of the first approach. Instead the second approach has a set of products which inherit from their own base class. In the first approach all the products had a common base class whereas in the second approach each set of class had their own base class. Also the factory in the second approach will have the methods to create more than one product. Confused? Lets take the same car e.g. and work it out to have a better understanding. As CD found out that different products will have different base classes and they inherit from them, he decided to rework his class structure. CD kept the same base class structure for the car hierarchy, in addition to that he introduced new classes called “Engine”, “Chassis”, “Axle”, and “Wheel” which an integral part of a car. To incorporate the new classes in car CD changed the base “Car” class as shown below.

using System;
using System.Collections.Generic;
using System.Text;
using Factory_Pattern.Car_Parts.Engine;
using Factory_Pattern.Car_Parts.Chassis;
using Factory_Pattern.Car_Parts.Axle;
using Factory_Pattern.Car_Parts.Wheel;

namespace Factory_Pattern.Products
{
    public abstract class Car
    {
        private IEngine _iEngine;
        private ICarChassis _iCarChassis;
        private IAxle _iAxle;
        private IWheel _iWheel;

        public IEngine Engine
        {
            get
            { return this._iEngine; }
            set
            { this._iEngine = value; }
        }

        public ICarChassis Chassis
        {
            get
            { return this._iCarChassis; }
            set
            { this._iCarChassis = value; }
        }

        public IAxle Axle
        {
            get
            { return this._iAxle; }
            set
            { this._iAxle = value; }
        }

        public IWheel Wheel
        {
            get
            { return this._iWheel; }
            set
            { this._iWheel = value; }
        }

        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; }
        }       
    }
}

You can see CD has added all the new parts of the car to the base abstract class. I need not explain why this approach was taken, as there can be no car without an engine, wheel etc. The abstract “Car” will form the base for all other Car classes. The class diagram with the inheritance is shown below.

image

One can see there is no change to the hierarchy other than the introduction of new properties. Next we can have a look at the different parts needed for the car. First we will see the wheel. The class diagram for wheel is shown below.

image

As one can see from the above diagram the base for wheel is an interface called IWheel. IWheel is inherited to the respective car’ wheel class, in the above case, it is inherited to HyundaiWheel class. From the “HyundaiWheel” the different model’ wheel has been extended. The code for the above implementation is pasted below.

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

namespace Factory_Pattern.Car_Parts.Wheel
{
    public interface IWheel
    {
        int Diameter { get; set; }
    }

    class HyundaiWheel : IWheel
    {
        #region IWheel Members

        int IWheel.Diameter
        {
            get
            {
                throw new Exception("The method or operation is not implemented.");
            }
            set
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }

        #endregion
    }

    class SantroWheel : HyundaiWheel
    {
    }

    class i10Wheel : HyundaiWheel
    {
    }

    class i20Wheel : HyundaiWheel
    {
    }

    class SonataWheel : HyundaiWheel
    {
    }

    class AccentWheel : HyundaiWheel
    {
    }
}

The above code is self explanatory. Next CD created engine. Here also the same concept is followed. An interface called IEngine which is implemented by the respective brand’ engine i.e. ToyotaEngine. ToyotaEngine is extended to implement the car specific engine like CamryEngine and CorollaEngine for Camry and Corolla models respectively. Why we have an interface for the engine is that every brand will have its own way of designing the engine, with interface we can give the freedom and also keep the contract in tact. Why we have a common class, ToyotaEngine, is that each brand will have there own common set of feature. The IEngine interface acts as the base for all the other cars engine. Honda implements IEngine to HondaEngine base class and then extends it to CityEngine, CivicEngine and AccordEngine. Similarly every brand follows the same concept.

image

 

image

The chassis also follows the same concept of an interface; interface implemented to a base class and then the base class is extended to create other model specific chassis.

image

Now this is an overkill of example I know but just to complete the car we need an axle also. The same concept is applied here also. I will not go into the details. CD has completed all the base classes needed for the abstract factory, now he has built the factories which will create these products.

The factory will have a base factory which again can be an interface or an abstract class and from this the other factories will implement/inherit the features. As CD already had an interface he decided to modify the “ICarFactory” interface used in the first implementation of abstract factory. To the “ICarFactory” he introduced four more methods to create the car engine (CreateEngine), to create car axle (CreateAxle), to create car chassis (CreateChassis) and finally to create wheel he incorporated “CreateWheel” method. After making changes to the interface CD implemented the interface to the car manufacturing factories. Few factories with the interface implementation are shown below.

image

As you can see the factories, HondaCivicFactory, FordFiestaFactory, HondaCityFactory and FordIkonFactory are implementing the interface ICarFactory. Similar to this all factories for the various models will implement the interface. The sample code for “FordFiestafactory” is shown below.

using System;
using System.Collections.Generic;
using System.Text;
using Factory_Pattern.Car_Parts;
using Factory_Pattern.Car_Parts.Axle;
using Factory_Pattern.Car_Parts.Chassis;
using Factory_Pattern.Car_Parts.Engine;
using Factory_Pattern.Car_Parts.Wheel;
using Factory_Pattern.Products;

namespace Factory_Pattern.Factory
{
    class FordFiestaFactory : ICarFactory
    {      
        Car ICarFactory.CreateCar(string theCarName)
        {
            return new Fiesta();                       
        }

        string CarModelsAvailable
        {
            get { return "Fiesta."; }
        }

        IAxle CreateAxle()
        {
            return new FiestaAxle();
        }

        ICarChassis CreateChassis()
        {
            return new FiestaChassis();
        }

        IEngine CreateEngine()
        {
            return new FiestaEngine();
        }

        IWheel CreateWheel()
        {
            return new FiestaWheel();
        }
    }
}

Next CD needed an assembling unit where the cars can be assembled. So CD created an “AssemblyFloor” class where cars can be assembled based on the dynamic factory passed. The AssemblyFloor code is shown below.

using System;
using System.Collections.Generic;
using System.Text;
using Factory_Pattern.Factory;
using Factory_Pattern.Products;

namespace Factory_Pattern
{
    class AssemblyFloor
    {
        ICarFactory carFactory;

        public AssemblyFloor(ICarFactory theCarFactory)
        {
            this.carFactory = theCarFactory;
        }

        public Car AssembleCar(string theCarName)
        {
            Car assembledCar = this.carFactory.CreateCar();
            assembledCar.Chassis = this.carFactory.CreateChassis();
            assembledCar.Engine = this.carFactory.CreateEngine();
            assembledCar.Axle = this.carFactory.CreateAxle();
            assembledCar.Wheel = this.carFactory.CreateWheel();
            return assembledCar;
        }
    }
}

With the AssemblyFloor CD finished his basic requirement for the abstract factory pattern. CD created “ShowRoom” class to test the working of the abstract factory implementation. Pasted below is the code of the “ShowRoom” class.

using System;
using System.Collections.Generic;
using System.Text;
using Factory_Pattern.Factory;
using Factory_Pattern.Products;

namespace Factory_Pattern
{
    class ShowRoom
    {      
        static void Main(string[] args)
        {
            Console.WriteLine("Please provide your brand preference? " +
                "Allowed values: Fiesta, Ikon, Fusion, i10, i20, santro, sonata etc.");
            string carName = Console.ReadLine();
            ICarFactory carFactory = CarFactoryCreator.CreateCarFactory(carName);
            AssemblyFloor assemblyFloor = new AssemblyFloor(carFactory);
            Car customerCar = assemblyFloor.AssembleCar(carName);
            Console.WriteLine("Your {0} car is ready to be delivered."
                , customerCar.CarName);
            Console.ReadLine();          
        }
    }
}

After implementing the above abstract factory pattern CD took his notepad to jot down the following.

GOF definition of abstract factory:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

What is the problem this pattern solves?

When you have set of related objects or dependent object then you go for Abstract Factory. As seen in the e.g. above we are creating related objects of car like engine, axle etc, so scenario similar to this can be solved using Abstract factory.

How it Solves the Problem?

To solve the problem we identify a set of related or dependent classes and provide a base class for these related classes to inherit. Then we define the Abstract Factory class and this class is inherited by concrete factories. The abstract factory class has the methods to create the related or dependent classes but the freedom is given to derive classes to implement their own ways of implementing the logic.

Participants of the Pattern.

  • Abstract Factory – in our e.g. the IcarFactory is the abstract factory.

  • Concrete Factory – FordFiestaFactory, FordIkonFactory, HondaCivicFactory etc are concrete factories

  • Abstract Product – Car, IWheel, IChassis, IEngine etc are e.g.

  • Product – Fiesta, Ikon, i10, i20, Camry, Corolla etc are e.gs.

  • Client – Assembly floor is the client.

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 Abstract Factory pattern and I hope the same is the case with the reader' of this blog.

In the next blog we will see the difference, CD found out between Factory and Abstract Factory pattern.

Love Patterns,

Sandeep

4 comments:

  1. Keep writing Sandy.. This really helps me understand the patterns in a much better way that I perceive it while reading a book.

    ReplyDelete
  2. Hi Sandeep,

    Nice to meet U here.

    you have made a very excellent presentation about design patterns which I am very much impressed. Keep sharing.

    regards
    Andrew G Avelin
    Visit us too @http://www.Only4gurus.org

    ReplyDelete
  3. Thanks Andrew. Nice to know you as well. Will keep this going.

    ReplyDelete
  4. Really Thankful for your time for sharing !

    ReplyDelete

Leave your valuable comments here.