Abstract Factory Design Pattern in C#

Abstract Factory Design Pattern in C# with Examples

In this article, I will discuss the Abstract Factory Design Pattern in C# with Examples. Please read our previous article discussing the Factory Method Design Pattern in C# with an example. The Abstract Factory Design Pattern belongs to the creational design pattern category and is one of the most used design patterns in real-world applications. As part of this article, we will discuss the following things.

  1. What is an Abstract Factory Design Pattern
  2. Example to understand the Abstract Factory Pattern
  3. Implementing Abstract Factory Design Pattern in C#
  4. When to use Abstract Factory Design Pattern.
  5. Abstract Factory Design Pattern Real-Time Examples.

What is the Abstract Factory Design Pattern?

According to the Gang of Four Definition, The Abstract Factory Design Pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.

The Abstract Factory design pattern is a creational pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.

Abstract means hiding some information, factory means which produces the products, and pattern means a design. So, the Abstract Factory Pattern is a software design pattern that provides a way to encapsulate a group of individual factories that have a common theme.

In simple words, we can say that the Abstract Factory is a super factory that creates other factories. This Abstract Factory is also called the Factory of Factories. That means the Abstract Factory design pattern provides an interface for creating families of related or dependent products but leaves the actual object creation to the concrete factory classes. If this is unclear now, don’t worry; we will explain this with one Real-time Example.

Example to Understand Abstract Factory Design Pattern:

Let us understand the Abstract Factory Design Pattern with one Real-Time Example. First, we will implement the example and then compare the Example with the Abstract Factory Design Pattern UML diagram so you can easily understand the concept.

We want to implement one application for showing the Car and Bike details. Here, we want to show two types of bikes, i.e., Regular Bikes and Sports Bikes, and the details of two types of cars, i.e., Regular and Sports cars. You must remember that a sports bike and car belong to the same family called Sports. Similarly, Regular Bikes and Regular Cars belong to the same family called Regular. With this kept in mind, let us proceed and see how we can implement this using the Abstract Factory Design Pattern in C#.

Abstract Factory Pattern Structure:
  • AbstractFactory: Declares an interface for operations that create abstract products. This will be an interface for operations that will create Abstract Product objects.
  • ConcreteFactory: Implements the operations to create concrete product objects. These classes implement the Abstract Factory interface and provide implementations for the interface methods. We can use these concrete classes to create concrete product objects.
  • AbstractProduct: Declares an interface for a type of product object. These are going to be interfaces for creating abstract products. Here, we need to define the Operations a Product should have.
  • ConcreteProduct: Implements the AbstractProduct interface. These are the classes that implement the Abstract Product interface.
  • Client: Uses interfaces declared by AbstractFactory and AbstractProduct classes. This class will use our Abstract Factory and Abstract Product interfaces to create a family of products.
Step 1: Creating Abstract Products

Here, we need to declare interfaces for creating abstract products. As we will create two types of familiar products, such as Bikes and Cars, here we need to create two interfaces or abstract classes representing each abstract product type. Here, I am going to create two interfaces.

IBike.cs (AbstractProductA)

Create an interface named IBike.cs and copy and paste the following code. This is going to be one of the Abstract Products. Each distinct product of the Bike product family should have a base interface. In this case, all variants of Bike products (SportsBike and RegularBike) must implement this IBike interface. As you can see, we have created the following interface with one abstract method. That method will be implemented by the subclasses (SportsBike and RegularBike) of the IBike interface.

namespace AbstractFactoryDesignPattern
{
    // The AbstractProductA interface
    // Each distinct product of the Bike product family should have a base interface.
    // All variants of Bike products must implement this IBike interface.
    public interface IBike
    {
        void GetDetails();
    }
}
ICar.cs (AbstractProductB)

Create an interface with ICar.cs and then copy and paste the following code. This is going to be our second Abstract Product. Each distinct product of the Car product family should have a base interface. In this case, all variants of the Car products (SportsCar and RegularCar) must implement this ICar interface. As you can see, we have created the following interface with one abstract method, which will be implemented by the subclasses of the ICar interface.

namespace AbstractFactoryDesignPattern
{
    // The 'AbstractProductB' interface
    // Each distinct product of the Car product family should have a base interface.
    // All variants of the Car products must implement this ICar interface.
    public interface ICar
    {
        void GetDetails();
    }
}
Step 2: Creating Concrete Products

Here, we must define the concrete product object the corresponding concrete factory will create. How the concrete factory will create the product object will be discussed later in the article when we discuss the concrete factory component. Remember that the concrete product classes must implement the Abstract Product Interface. In our example, the concrete product class must implement the IBike or ICar interface. So, as per our requirements, let us create four concrete products, i.e., RegularCar, SportsCar, RegularBike, and SportsBike.

RegularBike.cs (ProductA1)

Create a class file named RegularBike.cs, then copy and paste the following code. The following RegularBike Product Belongs to the Bike product family. As you can see, it implements the IBike interface and provides the implementation for the GetDetails method.

using System;
namespace AbstractFactoryDesignPattern
{
    // The ProductA1 class
    // Concrete Products are going to be created by corresponding Concrete Factories.
    // The following RegularBike Product Belongs to the Bike product family
    public class RegularBike : IBike
    {
        public void GetDetails()
        {
            Console.WriteLine("Fetching RegularBike Details..");
        }
    }
}
SportsBike.cs (ProductB1)

Create a class file named SportsBike.cs, then copy and paste the following code. The following SportsBike Product Belongs to the Bike product family. As you can see, it implements the IBike interface and provides implementations for the GetDetails method.

using System;
namespace AbstractFactoryDesignPattern
{
    // The ProductB1 class
    // Concrete Products are going to be created by corresponding Concrete Factories.
    // The following SportsBike Product Belongs to the Bike product family
    public class SportsBike : IBike
    {
        public void GetDetails()
        {
            Console.WriteLine("Fetching SportsBike Details..");
        }
    }
}
RegularCar.cs (ProductA2)

Create a class file named RegularCar.cs and copy and paste the following code. The following RegularCar Product Belongs to the Car product family. As you can see, it implements the ICar interface and provides implementations for the GetDetails method.

using System;
namespace AbstractFactoryDesignPattern
{
    // The ProductA2 class
    // Concrete Products are going to be created by corresponding Concrete Factories.
    // The following RegularCar Product Belongs to the Car product family
    public class RegularCar : ICar
    {
        public void GetDetails()
        {
            Console.WriteLine("Fetching RegularCar Details..");
        }
    }
}
SportsCar.cs (ProductB2)

Create a class file named SportsCar.cs and copy and paste the following code. The following SportsCar Product Belongs to the Car product family. As you can see, it implements the ICar interface and provides implementations for the GetDetails method.

using System;
namespace AbstractFactoryDesignPattern
{
    // The ProductB2 class
    // Concrete Products are going to be created by corresponding Concrete Factories.
    // The following SportsCar Product Belongs to the Car product family
    public class SportsCar : ICar
    {
        public void GetDetails()
        {
            Console.WriteLine("Fetching SportsCar Details..");
        }
    }
}
Step 3: Creating Abstract Factory

Here, we need to create an interface for operations that will create AbstractProduct objects. In our example, it is going to be IVehicleFactory. So, create a class file with the name IVehicleFactory.cs and then copy and paste the following. As you can see, this class contains two methods. The CreateBike method will create different variants of Bikes, whereas the CreateCar method will create different variants of Cars. The point you need to remember is here, we are only declaring the methods and returning the type of these two methods to be abstract products, i.e., ICar and IBike. Hence, from the child classes, we can create different objects (objects of subclasses of ICar and IBike).

namespace AbstractFactoryDesignPattern
{
    // The AbstractFactory interface
    // The Abstract Factory interface declares a set of methods that return different abstract products. 
    // These products are called a family. 
    // A family of products may have several variants
    public interface IVehicleFactory
    {
        //Abstract Product A
        IBike CreateBike();
        //Abstract Product B
        ICar CreateCar();
    }
}

Note: The above abstract factory class is used to create a family of other factories. Let us proceed and create such a family of factories.

Step 4: Creating Concrete Factories

Here, we must create concrete classes that implement the operations to create concrete product objects. These classes will implement the AbstractFactory interface and provide implementations for the two interface methods. In our example, we will create two Concrete Classes, i.e., RegularVehicleFactory and SportsVehicleFactory.

RegularVehicleFactory.cs (ConcreteFactory1)

The RegularVehicleFactory concrete class is going to create Regular Vehicle Concrete Products. In our example, the Regular Vehicle Concrete Products are RegularBike and RegularCar. So, create a class file named RegularVehicleFactory.cs and copy and paste the following code. If you notice, the signatures of the Concrete Factory’s methods return an abstract product (IBike) and (ICar), while inside the method, a concrete product (new RegularBike and new RegularCar) is instantiated. So, the following Concrete Factory Produces Regular Bike and Regular Car Products belong to the same Regular Family.

namespace AbstractFactoryDesignPattern
{
    // The ConcreteFactory1 class
    // Concrete Factories produce a family of products that belong to a single variant. 
    // The following Concrete Factory Produces Regular Bike and Car which are compatible
    // The signatures of the Concrete Factory's methods return an abstract product (IBike) and (ICar) 
    // while inside the method a concrete product (new RegularBike and new RegularCar) is instantiated.
    public class RegularVehicleFactory : IVehicleFactory
    {
        public IBike CreateBike()
        {
            return new RegularBike();
        }
        public ICar CreateCar()
        {
            return new RegularCar();
        }
    }
}
SportsVehicleFactory (ConcreteFactory2)

The SportsVehicleFactory concrete class is going to create Sports Vehicle Concrete Products. In our example, the Sports Vehicle Concrete Products are SportsBike and SportsCar. So, create a class file named SportsVehicleFactory.cs and copy and paste the following code. If you notice, the signatures of the Concrete Factory’s methods return an abstract product (IBike) and (ICar), while inside the method, a concrete product (new SportsBike and new SportsCar) is instantiated. So, the following Concrete Factory Produces Sports Bike and Sports Car Products that belong to the same Sports Family.

namespace AbstractFactoryDesignPattern
{
    // The ConcreteFactory2 class
    // Concrete Factories produce a family of products that belong to a single variant. 
    // The following Concrete Factory Produces Sports Bike and Sports Car which are compatible
    // The signatures of the Concrete Factory's methods return an abstract product (IBike) and (ICar) 
    // while inside the method a concrete product (new SportsBike and new SportsCar) is instantiated.
    public class SportsVehicleFactory : IVehicleFactory
    {
        public IBike CreateBike()
        {
            return new SportsBike();
        }
        public ICar CreateCar()
        {
            return new SportsCar();
        }
    }
}

Note: In our example, IVehicleFactory provides an interface to the client for creating families of related or dependent objects. Here, we have two concrete implementations of that interface – RegularVehicleFactory and SportsVehicleFactory classes. These two classes manufacture two different types of families of related objects, i.e., Bikes and Cars. RegularCar and RegularBike classes belong to the RegularVehicleFactory family. On the other hand, the SportsCar and SportsBike classes belong to a SportsVehicleFactory family.

Step 5: Client

The Client class uses AbstractFactory and AbstractProduct interfaces to create a family of related objects. In our example, it will be the Main method of the Program class. So, modify the Main method of the Program class as follows. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace AbstractFactoryDesignPattern
{
    //Client Code
    class Program
    {
        public static void Main()
        {
            // Fetch the Regular Bike and Car Details
            // Creating RegularVehicleFactory instance
            IVehicleFactory regularVehicleFactory = new RegularVehicleFactory();
            //regularVehicleFactory.CreateBike() will create and return Regular Bike
            IBike regularBike = regularVehicleFactory.CreateBike();
            regularBike.GetDetails();
            //regularVehicleFactory.CreateCar() will create and return Regular Car
            ICar regularCar = regularVehicleFactory.CreateCar();
            regularCar.GetDetails();

            // Fetch the Sports Bike and Car Details Created
            // Creating SportsVehicleFactory instance 
            IVehicleFactory sportsVehicleFactory = new SportsVehicleFactory();
            //sportsVehicleFactory.CreateBike() will create and return Sports Bike
            IBike sportsBike = sportsVehicleFactory.CreateBike();
            sportsBike.GetDetails();
            //sportsVehicleFactory.CreateCar() will create and return Sports Car
            ICar sportsCar = sportsVehicleFactory.CreateCar();
            sportsCar.GetDetails();

            Console.ReadKey();
        }
    }
}
Output:

Abstract Factory Design Pattern in C# with Examples

Abstract Factory Design Pattern UML (Class) Diagram:

Once we understand how to implement the Abstract Factory Design Pattern in C#, let us try to understand the UML (Unified Modeling Language) or Class diagram of the Abstract Factory Design Pattern. For a better understanding, please look at the following diagram, which shows the different components of the Abstract Factory Method Design Pattern. Here, on the right-hand side, I am comparing the Abstract Factory Design Pattern component with our example so that you can easily understand the different components of the Abstract Factory Design Pattern.

Abstract Factory Design Pattern UML (Class) Diagram

Let us understand each component of the Abstract Factory Design Pattern:

  1. Abstract Products: These are going to be interfaces for creating abstract products. Here, we need to define the Operations a Product should have. In our example, it is IBike.cs and ICar.cs interfaces.
  2. Concrete Products: These are the classes that implement the Abstract Product interface. In our example, RegularBike, SportsBike, RegularCar, and SportsCar classes are the Concrete Products.
  3. Abstract Factory: This will be an interface for operations that will create Abstract Product objects. In our example, it is going to be IVehicleFactory.
  4. Concrete Factory: These classes implement the AbstractFactory interface and provide implementations for the interface methods. In our example, RegularVehicleFactory and SportsVehicleFactory are the concrete factory classes.
  5. Client: It is the class that is going to use the Abstract Product and Abstract Factory to create a family of products. In our example, it is the Main method of the Program class.
Abstract Factory Components in Our Example
  1. Client: Main Method of Program Class
  2. Abstract Product A: IBike.cs
  3. Abstract Product B: ICar.cs
  4. ProductA1: RegularBike.cs
  5. ProductB1: SportsBike.cs
  6. ProductA2: RegularCar.cs
  7. ProductB2: SportsCar.cs
  8. Abstract Factory: IVehicleFactory.cs
  9. Concrete Factory1: RegularVehicleFactory.cs
  10. Concrete Factory2: SportsVehicleFactory.cs
Abstract Factory Design Pattern Real-Time Example in C#:

Let us Implement the Abstract Factory Design Pattern Real-Time Example in C# step by step with one Real-Time Example. We want to implement one application for showing the Course Details. Here, we want to show two types of courses, i.e., Front End Courses and Back End Courses. Again, we must also show how students will learn these courses, i.e., Sources. In this case, the source can be Online or Offline. Let us proceed and see how we can implement this application using the Abstract Factory Design Pattern in C#.

Step 1: Creating Abstract Products

Here, we need to declare interfaces for creating Abstract Products. As we will create two types of familiar products, such as Courses and Sources, here we need to create two interfaces or abstract classes representing each abstract product type. Here, I am going to create two interfaces.

ICourse.cs

Create an interface with the name ICourse.cs and then copy and paste the following code into it. This is going to be one of the Abstract Products. Each distinct product of the Course product family should have a base interface. In this case, all variants of Course products (Front-End and Back-End) must implement this ICourse interface. As you can see, we have created the following interface with three abstract methods, which will be implemented by the subclasses (FrontEndCourse and BackEndCourse).

namespace AbstractFactoryRealTimeExample
{
    // The AbstractProductA interface
    // Each distinct product of the Course product family should have a base interface.
    // All variants of Course products must implement this ICourse interface.
    public interface ICourse
    {
        string GetCourseName();
        int GetCourseFee();
        string GetCourseDuration();
    }
}
ISource.cs

Create an interface with the name ISource.cs and copy and paste the following code into it. This is going to be our second Abstract Product. Each distinct product of the ISource product family should have a base interface. In this case, all variants of the Source products (Online and Offline) must implement this ISource interface. As you can see, we have created the following interface with one abstract method. That method will be implemented by the subclasses (Online and Offline) of the ISource interface.

namespace AbstractFactoryRealTimeExample
{
    // The AbstractProductB interface
    // Each distinct product of the Source product family should have a base interface.
    // All variants of Source products must implement this ISource interface.
    public interface ISource
    {
        string GetSourceName();
    }
}
Step 2: Creating Concrete Products

Now, we need to define the concrete product object or the actual product object that the corresponding concrete factory will create. You must remember that these concrete product classes must implement the Abstract Product Interface and provide implementation to the Interface methods. In our example, the concrete product class must implement the ISource or ICourse interface. So, as per our requirements, let us create four concrete products, i.e., FrontEndCourse, BackEndCourse, Online, and Offline.

FrontEndCourse.cs

Create a class file named FrontEndCourse.cs and copy and paste the following code into it. The following FrontEndCourse Product Belongs to the Course product family. As you can see, it implements the ICourse interface and provides implementations for all three ICourse interface methods.

namespace AbstractFactoryRealTimeExample
{
    // The ProductA1 class
    // Concrete Products are going to be created by corresponding Concrete Factories.
    // The following FrontEndCourse Product Belongs to the Course product family
    public class FrontEndCourse : ICourse
    {
        public string GetCourseName()
        {
            return "HTML, CSS, and Bootstrap";
        }

        public string GetCourseDuration()
        {
            return "6 Months";
        }

        public int GetCourseFee()
        {
            return 2000;
        }
    }
}
BackEndCourse.cs

Create a class file named BackEndCourse.cs and copy and paste the following code. The following BackEndCourse Product Belongs to the Course product family. As you can see, it implements the ICourse interface and provides implementations for all three ICourse interface methods.

namespace AbstractFactoryRealTimeExample
{
    // The ProductB1 class
    // Concrete Products are going to be created by corresponding Concrete Factories.
    // The following BackEndCourse Product Belongs to the Course product family
    public class BackEndCourse : ICourse
    {
        public string GetCourseDuration()
        {
            return "6 Months";
        }

        public int GetCourseFee()
        {
            return 1000;
        }

        public string GetCourseName()
        {
            return "C#, Java, and Python";
        }
    }
}
Online.cs

Create a class file named Online.cs and copy and paste the following code. The following Online Product Belongs to the Source product family. As you can see, it implements the ISource interface and provides implementations for the GetSourceName method.

namespace AbstractFactoryRealTimeExample
{
    // The ProductA2 class
    // Concrete Products are going to be created by corresponding Concrete Factories.
    // The following Online Product Belongs to the Source product family
    public class Online : ISource
    {
        public string GetSourceName()
        {
            return "Dot Net Tutorials Zoom Classes";
        }
    }
}
Offline.cs

Create a class file named Offline.cs and copy and paste the following code. The following OfflineProduct Belongs to the Source product family. As you can see, it implements the ISource interface and provides implementations for the GetSourceName method.

namespace AbstractFactoryRealTimeExample
{
    // The ProductB2 class
    // Concrete Products are going to be created by corresponding Concrete Factories.
    // The following Offline Product Belongs to the Source product family
    public class Offline : ISource
    {
        public string GetSourceName()
        {
            return "Dot Net Tutorials Class Room Training";
        }
    }
}
Step 3: Creating Abstract Factory

Now, we need to create an interface for operations that will create Abstract Product objects. In our example, it is going to be ISourceCourseFactory. So, create a class file named ISourceCourseFactory.cs and copy and paste the following. As you can see, this class contains two methods, i.e., GetSource and GetCourse. The GetSource method will create different variants of Sources, whereas the GetCourse method will create different variants of Courses. The point you need to remember is here that we are only declaring that the methods and return type of these methods will be abstract products, i.e., ISource and ICourse. Hence, from the child classes, we can create different objects (objects of subclasses of ISource and ICourse).

namespace AbstractFactoryRealTimeExample
{
    // The AbstractFactory interface
    // The Abstract Factory interface declares a set of methods that return different abstract products. 
    // These products are called a family. 
    // A family of products may have several variants
    public interface ISourceCourseFactory
    {
        //Abstract Product A
        ISource GetSource();

        //Abstract Product B
        ICourse GetCourse();
    }
}
Step 4: Creating Concrete Factories

We must create concrete factory classes that implement abstract factory interfaces to create concrete product objects. In our example, we will create two Concrete Classes, i.e. OnlineSourceCourseFactory and OfflineSourceCourseFactory.

OnlineSourceCourseFactory.cs

The OnlineSourceCourseFactory concrete class will create Online Source and Course Concrete Products. In our example, the Online Source and Course Concrete Products are Online and BackEndCourse. So, create a class file named OnlineSourceCourseFactory.cs and copy and paste the following code. If you notice, the signatures of the Concrete Factory’s methods return an abstract product (ICourse) and (ISource), while inside the method, a concrete product (new Online and new BackEndCourse) is instantiated. So, the following Concrete Factory Produces Online Source and BackEndCourse Products belong to the same OnlineSourceCourse Family.

namespace AbstractFactoryRealTimeExample
{
    public class OnlineSourceCourseFactory : ISourceCourseFactory
    {
        public ISource GetSource()
        {
            return new Online();
        }
        public ICourse GetCourse()
        {
            return new BackEndCourse();
        }
    }
}
OfflineSourceCourseFactory.cs

The OfflineSourceCourseFactory concrete class will create Offline Source and Course Concrete Products. In our example, the Offline Source and Course Concrete Products are Offline and FrontEndCourse. So, create a class file named OfflineSourceCourseFactory.cs and then copy and paste the following code. If you notice, the signatures of the Concrete Factory’s methods return an abstract product (ICourse) and (ISource), while inside the method, a concrete product (new Offline and new FrintEndCourse) is instantiated. So, the following Concrete Factory Produces Offline Source and FrontEndCourse Products belong to the same OfflineSourceCourse Family.

namespace AbstractFactoryRealTimeExample
{
    public class OfflineSourceCourseFactory : ISourceCourseFactory
    {
        public ISource GetSource()
        {
            return new Offline();
        }
        public ICourse GetCourse()
        {
            return new FrontEndCourse();
        }
    }
}

Note: In our example, ISourceCourseFactory provides an interface to the client for creating families of related or dependent objects. Here, we have two concrete implementations of that interface, i.e., OnlineSourceCourseFactory and OfflineSourceCourseFactory classes. These two classes manufacture two different types of families of related objects, i.e., Courses and Sources. Online and BackEndCourse classes belong to the OnlineSourceCourse family. On the other hand, Offline and FrondEndCourse classes belong to the OfflineSourceCourse family.

Step 5: Client

The Client class uses AbstractFactory and AbstractProduct interfaces to create a family of related objects. In our example, it will be the Main method of the Program class. So, modify the Main method of the Program class as follows. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace AbstractFactoryRealTimeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Fetch the Front End Course and Source Details
            // Creating OfflineSourceCourseFactory instance
            ISourceCourseFactory offlineSourceCourseFactory = new OfflineSourceCourseFactory();

            //offlineSourceCourseFactory.GetCourse() will create and return FrondEndCourse object
            var course = offlineSourceCourseFactory.GetCourse();
            Console.WriteLine("Front End Course and Source Details");
            Console.WriteLine(course.GetCourseName());
            Console.WriteLine(course.GetCourseFee());
            Console.WriteLine(course.GetCourseDuration());

            //offlineSourceCourseFactory.GetSource() will create and return Offline object
            var source = offlineSourceCourseFactory.GetSource();
            Console.WriteLine(source.GetSourceName());

            //Same steps for Online Course and Source Details
            Console.WriteLine("\n----------------------\n");
            Console.WriteLine("Back End Course and Source Details");
            ISourceCourseFactory onlineSourceCourseFactory = new OnlineSourceCourseFactory();
            course = onlineSourceCourseFactory.GetCourse();
            Console.WriteLine(course.GetCourseName());
            Console.WriteLine(course.GetCourseFee());
            Console.WriteLine(course.GetCourseDuration());
            source = onlineSourceCourseFactory.GetSource();
            Console.WriteLine(source.GetSourceName());

            Console.ReadKey();
        }
    }
}
Output:

Abstract Factory Design Pattern Real-Time Example in C#

Abstract Factory Components in Our Example
  1. Client: Main Method of Program Class
  2. Abstract Product A: ICourse.cs
  3. Abstract Product B: ISource.cs
  4. ProductA1: FrontEndCourse.cs
  5. ProductB1: BackEndCourse.cs
  6. ProductA2: Online.cs
  7. ProductB2: Offline.cs
  8. Abstract Factory: ISourceCourseFactory.cs
  9. Concrete Factory1: OnlineSourceCourseFactory.cs
  10. Concrete Factory2: OfflineSourceCourseFactory.cs
Differences between Abstract Factory and Factory Method Design Pattern:
  1. Abstract Factory Design Pattern adds a layer of abstraction to the Factory Method Design Pattern
  2. The Abstract Factory design pattern implementation can have multiple factory methods
  3. Similar products of a factory implementation are grouped in the Abstract factory
  4. The Abstract Factory Pattern uses object composition to decouple applications from specific implementations
  5. The Factory Method Pattern uses inheritance to decouple applications from specific implementations
Advantages and Disadvantages of Abstract Factory Design Pattern in C#

The Abstract Factory design pattern is a popular creational pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. Here are the advantages and disadvantages of using the Abstract Factory design pattern:

Advantages of Abstract Factory Design Pattern in C#:
  • Consistency: The pattern ensures that the created families of products are consistent and compatible with each other. When you get a product from the factory, it’s guaranteed to work with the other products from the same family.
  • Separation of Concerns: The creation logic of the products is isolated from the client code. This separation makes the system architecture cleaner and easier to maintain.
  • Flexibility: By decoupling the client code from concrete product classes, you can change or extend the types of products the factory creates without altering client code.
  • Scalability: It’s easy to introduce new product families or variants by simply extending the existing factories or adding new ones. This makes the system scalable in terms of product variations.
  • Exchangeability: Client applications can switch between product families at runtime, allowing dynamic behavior based on configurations or environments.
Disadvantages of Abstract Factory Design Pattern in C#:
  • Complexity: Introducing new classes and interfaces for factories and products can increase the system’s complexity, especially when many product families exist.
  • Factory Proliferation: A new concrete factory must be created for each new family of products. This can lead to a proliferation of factory classes.
  • Change Requires Subclassing: Introducing a new product across all families may require changes to the abstract factory interface and potentially all of its concrete subclasses, violating the open/closed principle.
  • Initialization Overhead: The initialization process can be slightly heavier, especially when the system must decide between multiple product families during runtime.
  • Indirection: While the pattern helps achieve decoupling, it also introduces another layer of abstraction, making the system harder to understand for newcomers.

In conclusion, like any design pattern, the decision to use the Abstract Factory pattern should be based on the specific needs of your project. If your system needs to work with multiple families of related products and maintain consistency, the Abstract Factory pattern can be beneficial. However, simpler creational patterns or direct instantiation might suffice if the system’s requirements are straightforward and don’t involve complex product families.

In the next article, I will discuss the Abstract Factory Design Pattern Real-Time Examples in C#. In this article, I try to explain the Abstract Factory Design Pattern in C# with Examples. I hope this article will help you with your needs. I would like to have your feedback. Please post your feedback, questions, or comments about this article.

5 thoughts on “Abstract Factory Design Pattern in C#”

  1. Again below code violates the open closed principle.how cane we solve that?

    if we added new animal type

    namespace AbstractFactoryDesignPattern
    {
    public class LandAnimalFactory : AnimalFactory
    {
    public override Animal GetAnimal(string AnimalType)
    {
    if (AnimalType.Equals(“Dog”))
    {
    return new Dog();
    }
    else if (AnimalType.Equals(“Cat”))
    {
    return new Cat();
    }
    else if (AnimalType.Equals(“Lion”))
    {
    return new Lion();
    }
    else
    return null;
    }
    }
    }

    1. How does that violate the open-closed principle? Cause you create a new class and override the method which is called extension and you don’t change the existing class.

      1. Lakshitha Fernando

        Yes it is violating the OCP. As when a new land animal is introduced, the LandAnimalFactory has to modified, instead it should have a new class for it’s instantiation. As per the Factory Method pattern. sub class has the responsibility of instantiating its own instance.
        The correct implementation should be to have a factory method for each animal which is responsible for initializing its own object. (e.g. CatFactory, DogFactory etc.)

  2. Padam Agrawal

    Yes, I am bit confused as it is violating SRP principle? and could you please put some real enterprise example so that correlate .

  3. I think you could have take the previous credit card example to explain this. Could you please explain the same with the credit card example so that it will be easy to understand it and see the differences between factory method and abstract factory.

Leave a Reply

Your email address will not be published. Required fields are marked *