Sunday, October 1, 2023

Factory Design Pattern in C#

The Factory Design Pattern is one of the most frequently used design patterns in real-time applications. The Factory Design Pattern in C# falls under the Creational Design Patterns Category.

What is Factory Design Pattern in C#?

Let us first try to understand the definitions of the factory design pattern.

According to Gang of Four (GoF), the Factory Design Pattern states that A factory is an object used for creating other objects. In technical terms, we can say that a factory is a class with a method. That method will create and return different objects based on the received input parameter.

In simple words, when we have a main class(super class) and several different types of classes(subclasses) that are related to it, and we want to make an object from one of these related classes based on some information, we use something called the Factory Design Pattern in C#.

The Key Components:

  1. Product Interface/Abstract Class:This defines an interface or an abstract class for the products generated by the factories. Product classes usually share common attributes or methods.
  2. Concrete Products:These are the real-deal classes that implement the product interface. Each concrete product embodies a specific type of object.
  3. Factory Class:This class contains a method for creating objects.Typically, this method is named something like 'createProduct()' or 'factoryMethod()'.

Example to Understand Factory Design Pattern in C#

Let's dive into the Factory Design Pattern using a scenario of different beverages in a cafe.

Step-1 : Create the Abstract Product or Product Interface (Beverage)

We need to create either an interface or an abstract class that will expose the operations a beverage should have. So, create a interface file named IBeverage.cs and copy and paste the following code.

 public interface IBeverage
    {
        public string Serve();
    }

Now We will create two Product classes to implement the above interface.

Step-2 : Creating Product Classes(Coffee and Tea)

In our example we will take two beverage products- Coffee and Tea. So we will create two classes by implementing the IBeverage.cs interface. Thse two classes will be:- Coffee.cs and Tea.cs

Coffee.cs
 public class Coffee : IBeverage
    {
        public string Serve()
        {
            return "Serving Coffee";
        }
    }
Tea.cs
 public class Tea:IBeverage
    {
        public string Serve()
        {
            return "Serving Tea";
        }
    }

So, we have created two Product classes Coffee.cs and Tea.cs that implements the IBeverage.cs interface. Now we will create the Factory class.

Step-3 : Creating Factory Class(BeverageFactory)

Create a class file named BeverageFactory.cs.This class will contain the logic to create and initialize the appropriate object and returns that object based on some condition. As you can see, this class contains one static method. That static method takes one string parameter, and based on the parameter value, it will create and return the appropriate product instance (Coffee, or Tea) to the client.

 public class BeverageFactory
    {        
        public static IBeverage GetBeverage(string beverageName)
        {
            IBeverage beverage = null;
            if (beverageName == "Coffee")
            {
                beverage = new Coffee();
            }
            else if (beverageName == "Tea")
            {
                beverage = new Tea();
            }
            return beverage;
        }
    }

Step-4 : Using factory class in client to get the product instance

Now we need to use the Factory class in our client class(in our example it in Program.cs) as follows

using FactoryDesignPatternDemo.Factory;
using FactoryDesignPatternDemo.Product;

IBeverage beverage = BeverageFactory.GetBeverage("Coffee");
if (beverage != null)
{
    Console.WriteLine(beverage.Serve());
    Console.WriteLine("Press any key...");
    Console.ReadLine();
}

As you can see, we are calling the Static GetBeverage method of the BeverageFactory class by passing the Beverage Type which instance we need to create. Once the GetBeverage method returns the appropriate product instance, we consume the methods as it is

Output

factory design pattern

UML(Class) Diagram

Factory Design Pattern UML

Problems of Simple Factory Pattern

  1. If we need to add any new product (i.e., a new beverage), then we need to add a new if else condition in the GetBeverage method of the BeverageFactory class. This violates the open/closed design principle.
  2. We also have a tight coupling between the Factory (BeverageFactory) and Product classes (Coffee and Tea). We can overcome these problems using the Factory Method Design Pattern, which we will discuss in our upcoming articles.

Advantages of Factory Design Pattern in C#:

  • Decoupling: The Factory Design Pattern promotes decoupling. The client code is decoupled from the specific classes it needs to instantiate, which helps achieve the principle of “separation of concerns.”
  • Flexibility: It offers flexibility in terms of which class to instantiate. If we need to change the instantiation logic or introduce new classes, we only need to change the factory, leaving the client code untouched.
  • Consistent Object Creation: Having a central place for object creation ensures that all objects are created consistently, following the same rules or configurations.
  • Single Responsibility Principle: By delegating the responsibility of object creation to factories, the main business logic classes can focus on their primary responsibilities.
  • Easy to Test: Factories can facilitate testing. During unit testing, we can easily mock objects or swap real implementations with stubs.
  • Code Reusability: Factories can be reused across different application parts, ensuring the same object creation logic is employed everywhere.

To sum it up, the Factory Design Pattern is a potent tool for handling object creation in a versatile and maintainable manner. It is a widely embraced approach in software development, especially for managing object creation in intricate systems. Understanding and implementing this pattern can significantly enhance the design and maintainability of your code.

The full source code is available here:

Happy coding!! 😊

No comments:

Post a Comment

^ Scroll to Top