Skip to main content

Factory Design Pattern

Factory Design Pattern is a type of Creational Design Pattern.

Creational Design Pattern  deals with creation of object such that they can be decoupled from their implementing system. Using this design pattern it is very easy to decide which objects needs to be created for a given scenario. 

Factory Pattern returns an instance of one of several possible classes, depending on the data 
Factory pattern accepts a parameter depending of this parameter it returns one of the several possible classes. These possible classes have same parent class and method but each has different implementation.

Real time reason to implement Factory Pattern and why not directly create objects with constructor calls ? ?

For simple code I also would suggest not yo use factory. Sometimes it is better to not to use any design pattern as design patterns introduces some level of complexity in the code. But for large applications where many developers are working any many code changes are expected, it is recommended to use factory. Still, I haven't answered the main question Why Factory ?  Don't worry...I will answer in a while..It is very important design pattern and I don't want you to learn in a hurry.

Let me try to answer you some potential reasons to use factory:

With constructor approach to create an object, at some point of time the constructor may require different number of parameters which will cause client to change code everywhere ( tight coupling ).

Separation of concern : Business classes needs to use complex objects but they need not to know how they created before using it.

Another design related reason can be Open/Close Principle Let's take a simple case of database, If the back-end being used  in your application is SQL Server and in nearest future you need to change it to Oracle you would need to modify your code.

Another obvious reason is you may not know in advance which concrete class needs to be created.

I have seen the below kind of code at my places, is this a Factory ? Nooo.... This is not a Factory.

Of course based on some creational logic it will return the int value but let's go back to Factory Definition, Factory always returns abstraction i.e. an interface or an abstract class.

int bonus= BonusFactory.CalculateEmployeeBonus(input employeeBonusRequest);


To be continued ......., I have doctor's appointment, I ll try to finish implementation by tonight.

I came back ..ll resume writing this blog, Let's do some Lab session and understand the Factory .

Take Vehicles example, all the vehicles has Start and Stop Operation.

public interface IVehicle
{
    string VehicleName { get; }
    void Start();
    void Stop();
}


Some Vehicles:

public class Car : IVehicle
{
public string VehicleName
        {
            get { return "Car"; }
        }
        public void Start()
        {
            Console.WriteLine("I am a car and I am going to start.");
        }
        public void Stop()
        {
            Console.WriteLine("I am a Car and I am going to stop");
        }
}

public class Truck: IVehicle
{
public string VehicleName
        {
            get { return "Truck"; }
        }
        public void Start()
        {
            Console.WriteLine("I am a Truck and I am going to start.");
        }
        public void Stop()
        {
            Console.WriteLine("I am a Truck and I am going to stop");
        }
}

public class Bus : IVehicle { public string VehicleName { get { return "Bus"; } } public void Start() { Console.WriteLine("I am a Bus and I am going to start."); } public void Stop() { Console.WriteLine("I am a Bus and I am going to stop"); } } public class Tempo : IVehicle { public string VehicleName { get { return "Tempo"; } } public void Start() { Console.WriteLine("I am a Tempo and I am going to start."); } public void Stop() { Console.WriteLine("I am a Tempo and I am going to stop"); } }
Program class implementation :

  class Program
    {
        static void Main(string[] args)
        {
            string vehicleName = args[0];
            IVehicle vehicle = GetVehicle(vehicleName);
            vehicle.Start();
            vehicle.Stop();
            Console.ReadKey();
        }

        private static IVehicle GetVehicle(string vehichleName)
        {
            switch (vehichleName)
            {
                case "Car":
                    return new Car();
                case "Truck":
                    return new Truck();
                case "Bus":
                    return new Bus();
                case "Tempo":
                    return new Tempo();
                default:
                    throw new Exception("No such vehicle found");
            }
        }
    }

Run this Program with argument as Car










Output:









Perfect!! expected output...Now Is this a Factory ?

Let me answer this in  a while. Consider we have some another vehicle type i.e. Bike

public class Bike: IVehicle
{
     public string VehicleName
        {
            get { return "Bike"; }
        }
        public void Start()
        {
            Console.WriteLine("I am a Bike and I am going to start.");
        }
        public void Stop()
        {
            Console.WriteLine("I am a Bike and I am going to stop");
        }
}

We have to extend switch case , Oh! again it is a violation of Open/Closed principle. Also Program.cs should be aware of new implementation of IVehicle as this is responsible to find the correct concrete type, ideally Program.cs should just understand IVehicle interface. Before defining the solution of these issues let me answer you the question Is this a Factory ? Yes, This is a Factory or say Simple Factory with some disadvantages I already discussed.

Potential Solution : 

Factory Method : lets a class defer instantiation to sub classes.

Just add some code and modify Program class.

Add interface for Factory and create Factory for each Type

 public interface IVehicleFactory
        {
            IVehicle CreateVehicle();
        }

    public class CarFactory : IVehicleFactory
    {
        public IVehicle CreateVehicle()
        {
            return new Car();
        }
    }

    public class BusFactory : IVehicleFactory
    {
        public IVehicle CreateVehicle()
        {
            return new Bus();
        }
    }

    public class TruckFactory : IVehicleFactory
    {
        public IVehicle CreateVehicle()
        {
            return new Truck();
        }
    }
    public class TempoFactory : IVehicleFactory
    {
        public IVehicle CreateVehicle()
        {
            return new Tempo();
        }
    }
Modify Program class:

class Program
    {
        static void Main(string[] args)
        {
            string vehichleName = args[0];
            if(vehicleName.Equals("Car")){
            IVehicleFactory factory = new CarFactory();
            var car=factory.CreateVehicle();
            car.Start();
            car.Stop();
       }
        }
    }

That's it!! Factory Method is implemented
You want to add anther type, Bike ? Add a separate Factory for it and you are done, no chance in factory is required. Also, Program class calls CarFactory (Factory Method) without knowing how and what actual type of the object was created.

Some more on Factory Design Pattern - Different Flavor and usage

Factory with Reflection...

Just Keep IVehicle Interface and Concrete Classes, remove all other code

Below is the modified Factory class

public class VehicleFactory
    {
        Dictionary<string, Type> vehicles;
        public VehicleFactory()
        {
            LoadTypesICanReturn();
        }
        public IVehicle CreateInstance(string vehicleName)
        {
            Type t = GetTypeToCreate(vehicleName);
            if (t == null)
                throw new Exception("Bad Type");
            else
                return Activator.CreateInstance(t) as IVehicle;
        }
        private Type GetTypeToCreate(string vehicleName)
        {
            foreach (var vehicle in vehicles)
            {
                if (vehicle.Key.Contains(vehicleName))
                {
                    return vehicles[vehicle.Key];
                }
            }
            return null;
        }
        private void LoadTypesICanReturn()
        {
            vehicles = new Dictionary<string, Type>();
            Type[] typeInThisAssembly = Assembly.GetExecutingAssembly().GetTypes();
            foreach (Type type in typeInThisAssembly)
            {
                if (type.GetInterface(typeof(IVehicle).ToString())!=null)
                {
                    vehicles.Add(type.Name.ToLower(), type);
                }
            }
        }
    }
Accordingly Program class will get changed
  class Program
    {
        static void Main(string[] args)
        {
            string vehicleName = args[0];
            VehicleFactory factory = new VehicleFactory();
            IVehicle vehicle= factory.CreateInstance(vehicleName);
            vehicle.Start();
            vehicle.Stop();
            Console.ReadKey();
        }
    }
Note: We are converting args[0] value in toLower()

With this solution also, we don't need to extend Factory class, any new type would be taken care by reflection.Program.cs is not any longer aware of the concrete Vehicle types.

In the above 2 solutions i.e Factory Method and Factory with Reflection the problem we can say is Caller is aware of which factory is getting called which is introducing unnecessary coupling between calling client and concrete class. The Type of Factory should be hidden.

Solution with abstract Factory:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Vehicles
{
    class Program
    {
        static void Main(string[] args)
        {
            string description = args[0];
            IVehicleFactory vehicleFactory = LoadFactory();
            IVehicle vehicle= vehicleFactory.CreateInstance(description);
            vehicle.Start();
            vehicle.Stop();
            Console.ReadKey();
        }
        private static IVehicleFactory LoadFactory()
        {
            string factoryName = Properties.Settings.Default.DefaultVehicleFactory;
            return Assembly.GetExecutingAssembly().CreateInstance(factoryName) as IVehicleFactory;
        }
    }
    public interface IVehicle
    {
        string VehicleName { get; }
        void Start();
        void Stop();
    }
    public class Car : IVehicle
    {
        public string VehicleName
        {
            get { return "Car"; }
        }
        public void Start()
        {
            Console.WriteLine("I am a car and I am going to start.");
        }
        public void Stop()
        {
            Console.WriteLine("I am a Car and I am going to stop");
        }
    }
    public class Truck : IVehicle
    {
        public string VehicleName
        {
            get { return "Truck"; }
        }
        public void Start()
        {
            Console.WriteLine("I am a Truck and I am going to start.");
        }
        public void Stop()
        {
            Console.WriteLine("I am a Truck and I am going to stop");
        }
    }
    public class Bus : IVehicle
    {
        public string VehicleName
        {
            get { return "Bus"; }
        }
        public void Start()
        {
            Console.WriteLine("I am a Bus and I am going to start.");
        }
        public void Stop()
        {
            Console.WriteLine("I am a Bus and I am going to stop");
        }
    }
    public class Tempo : IVehicle
    {
        public string VehicleName
        {
            get { return "Tempo"; }
        }
        public void Start()
        {
            Console.WriteLine("I am a Tempo and I am going to start.");
        }
        public void Stop()
        {
            Console.WriteLine("I am a Tempo and I am going to stop");
        }
    }
    public class VehicleFactory : IVehicleFactory
    {
        Dictionary<string, Type> vehicles;
        public VehicleFactory()
        {
            LoadTypesICanReturn();
        }
        public IVehicle CreateInstance(string vehicleName)
        {
            Type t = GetTypeToCreate(vehicleName);
            if (t == null)
                throw new Exception("Bad Type");
            else
                return Activator.CreateInstance(t) as IVehicle;
        }
        private Type GetTypeToCreate(string vehicleName)
        {
            foreach (var vehicle in vehicles)
            {
                if (vehicle.Key.Contains(vehicleName))
                {
                    return vehicles[vehicle.Key];
                }
            }
            return null;
        }
        private void LoadTypesICanReturn()
        {
            vehicles = new Dictionary<string, Type>();
            Type[] typeInThisAssembly = Assembly.GetExecutingAssembly().GetTypes();
            foreach (Type type in typeInThisAssembly)
            {
                if (type.GetInterface(typeof(IVehicle).ToString())!=null)
                {
                    vehicles.Add(type.Name.ToLower(), type);
                }
            }
        }
    }
    public interface IVehicleFactory
    {
        IVehicle CreateInstance(string description);
    }

}

Here I have just defined the basic idea of Abstract Factory, For more on Abstract Factory I insist you to read my another article on Abstract Factory













Comments

Popular posts from this blog

Abstract Factory Design Pattern

Abstract Factory : return families of related or dependent objects without specifying their concrete classes. AbstractFactory- IVehicle ConcreteFactory - Maruti, Honda AbstractProduct- IDiesel, IPetrol Product- DezirePetrol, ZenDiesel, AmazeDiesel, CityPetrol Client- This is a class which uses AbstractFactory and AbstractProduct interfaces to create a family of related objects Implementation is pretty much straight forward: Since now you have good understanding of Factory, there is nothing much to explain. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AbstractFactory {     class Program     {         static void Main(string[] args)         {             IVehicle marutiVehicle = new Maruti();             CarClient marutiClient = new CarClient(marutiVehicle); ...

Database Factory Design Pattern C#

Many developers has confusion on how to write database code in application. I will discuss several approaches here and try to provide explanation on each approach. Approach 1 : Easiest approach which is very straight forward which will work absolutely fine. The issues we will get to manage the project in terms of software principles. Like if you going to change Database provider, you would need to change using statements and other issue like mixing Database code with business logic etc. I will not go in detail here, I am assuming you already have an understanding of design principles. I am just exploring different approaches to achieve the database connectivity. using System.Collections.Generic; using System.Data.SqlClient; namespace DatabaseFactory {     class Program     {         static void Main(string[] args)         {             var employees = SomeDabOperation();   ...

Dependency Injection and Inversion Of Control C# - Par 2 (Implementation)

Before going through this post, I suggest you to go through my previous post on basic concepts in Dependency injection and Inversion of control. Demo on product. This demo is based on a traditional implementation approach: We have a Product class and it has a method which takes the discount and based on some business logic it applies the discount on the product. Product service will interact with database using ProductRepository. If you will notice ProductService has dependency on 2 concrete classes i.e. Discount and ProductRepository new Discount(); new ProductRepository(); We can hence say that ProductService is tightly coupled because of these 2 dependencies. We may require to use different discount based on several factors such as Product type, Some Festival or any other factor. Based on different discounts we may need to change ProductService class also in future you may change the database from SQL to Oracle, Again it may require ProductService changes which is viol...