Factory Design Pattern In C#

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

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

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

For simple code, I also would suggest not to use Factory. Sometimes, it is better to not to use any design pattern as design patterns introduce some level of complexity in the code. But for large applications where many developers are working and 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 one of the very important design patterns 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 creating an object, at some point in time, the constructor may require a different number of parameters which will cause the client to change the code everywhere (tight coupling).

Separation of concern

Business classes need to use complex objects but they need not know how they created before using it. Another design-related reason can be Open/Closed Principle.

Let's take a simple case of a 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? No.... 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.

  1. int bonus= BonusFactory.CalculateEmployeeBonus(input employeeBonusRequest);  
Let's do some lab session and understand the Factory. 

Take an example of vehicles. All the vehicles have Start and Stop operations.

  1. public interface IVehicle {  
  2.     string VehicleName {  
  3.         get;  
  4.     }  
  5.     void Start();  
  6.     void Stop();  
  7. }  
Some Vehicles
  1. public class Car: IVehicle {  
  2.     public string VehicleName {  
  3.         get {  
  4.             return "Car";  
  5.         }  
  6.     }  
  7.     public void Start() {  
  8.         Console.WriteLine("I am a car and I am going to start.");  
  9.     }  
  10.     public void Stop() {  
  11.         Console.WriteLine("I am a Car and I am going to stop");  
  12.     }  
  13. }  
  14. public class Truck: IVehicle {  
  15.     public string VehicleName {  
  16.         get {  
  17.             return "Truck";  
  18.         }  
  19.     }  
  20.     public void Start() {  
  21.         Console.WriteLine("I am a Truck and I am going to start.");  
  22.     }  
  23.     public void Stop() {  
  24.         Console.WriteLine("I am a Truck and I am going to stop");  
  25.     }  
  26. }  
  27. public class Bus  
  28.   
  29. IVehicle {  
  30.     public string VehicleName {  
  31.         get {  
  32.             return "Bus";  
  33.         }  
  34.     }  
  35.     public void Start() {  
  36.         Console.WriteLine("I am a Bus and I am going to start.");  
  37.     }  
  38.     public void Stop() {  
  39.         Console.WriteLine("I am a Bus and I am going to stop");  
  40.     }  
  41. }  
  42. public class Tempo: IVehicle {  
  43.     public string VehicleName {  
  44.         get {  
  45.             return "Tempo";  
  46.         }  
  47.     }  
  48.     public void Start() {  
  49.         Console.WriteLine("I am a Tempo and I am going to start.");  
  50.     }  
  51.     public void Stop() {  
  52.         Console.WriteLine("I am a Tempo and I am going to stop");  
  53.     }  

Program class implementation

  1. class Program {  
  2.     static void Main(string[] args) {  
  3.         string vehicleName = args[0];  
  4.         IVehicle vehicle = GetVehicle(vehicleName);  
  5.         vehicle.Start();  
  6.         vehicle.Stop();  
  7.         Console.ReadKey();  
  8.     }  
  9.     private static IVehicle GetVehicle(string vehichleName) {  
  10.         switch (vehichleName) {  
  11.             case "Car":  
  12.                 return new Car();  
  13.             case "Truck":  
  14.                 return new Truck();  
  15.             case "Bus":  
  16.                 return new Bus();  
  17.             case "Tempo":  
  18.                 return new Tempo();  
  19.             default:  
  20.                 throw new Exception("No such vehicle found");  
  21.         }  
  22.     }  
  23. }  

Run this Program with an argument as Car.

Angular

Output

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.

  1. public class Bike: IVehicle {  
  2.     public string VehicleName {  
  3.         get {  
  4.             return "Bike";  
  5.         }  
  6.     }  
  7.     public void Start() {  
  8.         Console.WriteLine("I am a Bike and I am going to start.");  
  9.     }  
  10.     public void Stop() {  
  11.         Console.WriteLine("I am a Bike and I am going to stop");  
  12.     }  
  13. }  

We have to extend the switch case. Oh! again it is a violation of Open/Closed principle. Also P, ogram.cs should be aware of the 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.

Factory Method lets a class defer instantiation to subclasses. Just add some code and modify the Program class.

Add interface for Factory and create Factory for each Type.

  1. public interface IVehicleFactory {  
  2.     IVehicle CreateVehicle();  
  3. }  
  4. public class CarFactory: IVehicleFactory {  
  5.     public IVehicle CreateVehicle() {  
  6.         return new Car();  
  7.     }  
  8. }  
  9. public class BusFactory: IVehicleFactory {  
  10.     public IVehicle CreateVehicle() {  
  11.         return new Bus();  
  12.     }  
  13. }  
  14. public class TruckFactory: IVehicleFactory {  
  15.     public IVehicle CreateVehicle() {  
  16.         return new Truck();  
  17.     }  
  18. }  
  19. public class TempoFactory: IVehicleFactory {  
  20.     public IVehicle CreateVehicle() {  
  21.         return new Tempo();  
  22.     }  
  23. }  

Modify Program class

  1. class Program {  
  2.     static void Main(string[] args) {  
  3.         string vehichleName = args[0];  
  4.         if (vehicleName.Equals("Car")) {  
  5.             IVehicleFactory factory = new CarFactory();  
  6.             var car = factory.CreateVehicle();  
  7.             car.Start();  
  8.             car.Stop();  
  9.         }  
  10.     }  
  11. }  

That's it!! Factory Method is implemented.

Do you want to add another type, Bike? Add a separate Factory for it and you are done. No change in Factory is required. Also, the 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 Flavors and usage -

Factory with Reflection...

Just Keep IVehicle Interface and Concrete Classes and remove all the other code.

Below is the modified Factory class

  1. public class VehicleFactory {  
  2.     Dictionary < string, Type > vehicles;  
  3.     public VehicleFactory() {  
  4.         LoadTypesICanReturn();  
  5.     }  
  6.     public IVehicle CreateInstance(string vehicleName) {  
  7.         Type t = GetTypeToCreate(vehicleName);  
  8.         if (t == nullthrow new Exception("Bad Type");  
  9.         else return Activator.CreateInstance(t) as IVehicle;  
  10.     }  
  11.     private Type GetTypeToCreate(string vehicleName) {  
  12.         foreach(var vehicle in vehicles) {  
  13.             if (vehicle.Key.Contains(vehicleName)) {  
  14.                 return vehicles[vehicle.Key];  
  15.             }  
  16.         }  
  17.         return null;  
  18.     }  
  19.     private void LoadTypesICanReturn() {  
  20.         vehicles = new Dictionary < string, Type > ();  
  21.         Type[] typeInThisAssembly = Assembly.GetExecutingAssembly().GetTypes();  
  22.         foreach(Type type in typeInThisAssembly) {  
  23.             if (type.GetInterface(typeof(IVehicle).ToString()) != null) {  
  24.                 vehicles.Add(type.Name.ToLower(), type);  
  25.             }  
  26.         }  
  27.     }  
  28. }  

Accordingly, Program class will get changed.

  1. class Program {  
  2.     static void Main(string[] args) {  
  3.         string vehicleName = args[0];  
  4.         VehicleFactory factory = new VehicleFactory();  
  5.         IVehicle vehicle = factory.CreateInstance(vehicleName);  
  6.         vehicle.Start();  
  7.         vehicle.Stop();  
  8.         Console.ReadKey();  
  9.     }  
  10. }  

Note - We are converting args[0] value in to Lower().

With this solution also, we don't need to extend Factory class; any new type would be taken care by reflectionProgram.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, and which one is introducing unnecessary coupling between calling client and concrete class. So, the type of Factory should be hidden.

Solution with abstract Factory

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Reflection;  
  5. using System.Text;  
  6. using System.Threading.Tasks;  
  7. namespace Vehicles {  
  8.     class Program {  
  9.         static void Main(string[] args) {  
  10.             string description = args[0];  
  11.             IVehicleFactory vehicleFactory = LoadFactory();  
  12.             IVehicle vehicle = vehicleFactory.CreateInstance(description);  
  13.             vehicle.Start();  
  14.             vehicle.Stop();  
  15.             Console.ReadKey();  
  16.         }  
  17.         private static IVehicleFactory LoadFactory() {  
  18.             string factoryName = Properties.Settings.Default.DefaultVehicleFactory;  
  19.             return Assembly.GetExecutingAssembly().CreateInstance(factoryName) as IVehicleFactory;  
  20.         }  
  21.     }  
  22.     public interface IVehicle {  
  23.         string VehicleName {  
  24.             get;  
  25.         }  
  26.         void Start();  
  27.         void Stop();  
  28.     }  
  29.     public class Car: IVehicle {  
  30.         public string VehicleName {  
  31.             get {  
  32.                 return "Car";  
  33.             }  
  34.         }  
  35.         public void Start() {  
  36.             Console.WriteLine("I am a car and I am going to start.");  
  37.         }  
  38.         public void Stop() {  
  39.             Console.WriteLine("I am a Car and I am going to stop");  
  40.         }  
  41.     }  
  42.     public class Truck: IVehicle {  
  43.         public string VehicleName {  
  44.             get {  
  45.                 return "Truck";  
  46.             }  
  47.         }  
  48.         public void Start() {  
  49.             Console.WriteLine("I am a Truck and I am going to start.");  
  50.         }  
  51.         public void Stop() {  
  52.             Console.WriteLine("I am a Truck and I am going to stop");  
  53.         }  
  54.     }  
  55.     public class Bus: IVehicle {  
  56.         public string VehicleName {  
  57.             get {  
  58.                 return "Bus";  
  59.             }  
  60.         }  
  61.         public void Start() {  
  62.             Console.WriteLine("I am a Bus and I am going to start.");  
  63.         }  
  64.         public void Stop() {  
  65.             Console.WriteLine("I am a Bus and I am going to stop");  
  66.         }  
  67.     }  
  68.     public class Tempo: IVehicle {  
  69.         public string VehicleName {  
  70.             get {  
  71.                 return "Tempo";  
  72.             }  
  73.         }  
  74.         public void Start() {  
  75.             Console.WriteLine("I am a Tempo and I am going to start.");  
  76.         }  
  77.         public void Stop() {  
  78.             Console.WriteLine("I am a Tempo and I am going to stop");  
  79.         }  
  80.     }  
  81.     public class VehicleFactory: IVehicleFactory {  
  82.         Dictionary < string, Type > vehicles;  
  83.         public VehicleFactory() {  
  84.             LoadTypesICanReturn();  
  85.         }  
  86.         public IVehicle CreateInstance(string vehicleName) {  
  87.             Type t = GetTypeToCreate(vehicleName);  
  88.             if (t == nullthrow new Exception("Bad Type");  
  89.             else return Activator.CreateInstance(t) as IVehicle;  
  90.         }  
  91.         private Type GetTypeToCreate(string vehicleName) {  
  92.             foreach(var vehicle in vehicles) {  
  93.                 if (vehicle.Key.Contains(vehicleName)) {  
  94.                     return vehicles[vehicle.Key];  
  95.                 }  
  96.             }  
  97.             return null;  
  98.         }  
  99.         private void LoadTypesICanReturn() {  
  100.             vehicles = new Dictionary < string, Type > ();  
  101.             Type[] typeInThisAssembly = Assembly.GetExecutingAssembly().GetTypes();  
  102.             foreach(Type type in typeInThisAssembly) {  
  103.                 if (type.GetInterface(typeof(IVehicle).ToString()) != null) {  
  104.                     vehicles.Add(type.Name.ToLower(), type);  
  105.                 }  
  106.             }  
  107.         }  
  108.     }  
  109.     public interface IVehicleFactory {  
  110.         IVehicle CreateInstance(string description);  
  111.     }  
  112. }  

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.

Ebook Download
View all
Learn
View all