Sunday, November 5, 2023

Abstract Factory Design Pattern in C#

In this article, I will explain the Abstract Factory Design Pattern in C# with practical examples. I encourage you to check out our previous article, which covers the Factory Design Pattern in C# along with an example.The Abstract Factory Design Pattern falls under the category of creational design patterns and is widely applied in real-world software development. In this article, we'll explore the following topics

What is the Abstract Factory Design Pattern?

The Abstract Factory Design Pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. It is a higher-level pattern than the Factory Method pattern, which deals with creating individual objects, while the Abstract Factory creates families of objects.

"Abstract" means hiding details, "Factory" refers to the entity that creates things, and "Pattern" indicates a design approach. Therefore, the Abstract Factory Pattern is a method in software design that allows you to wrap a set of factories with a shared theme.

Put simply, the Abstract Factory serves as a high-level factory that generates other factories. It's often referred to as the "Factory of Factories." This design pattern, the Abstract Factory, offers a way to create groups of related products without specifying the actual objects to be created.

Components of the Abstract Factory Pattern

  1. Abstract Factory:This is an interface or an abstract class that declares a set of methods for creating a family of related objects. Each method typically corresponds to a different product or object type.
  2. Concrete Factories:These are concrete implementations of the abstract factory interface. Each concrete factory is responsible for creating a specific family of related objects.
  3. Abstract Products:These are interfaces or abstract classes that declare the methods that concrete product classes must implement.
  4. Concrete Products:These are the actual classes that implement the abstract product interfaces. There can be multiple concrete product classes for each abstract product.
  5. 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.

Understand Abstract Factory Design Pattern Through Example

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 Button and Textboax, here we need to create two interfaces or abstract classes representing each abstract product type. Here, I am going to create two interfaces.

IButton.cs
namespace AbstractFactoryPatternExample.Product.Button
{
    public interface IButton
    {
        void Render();
    }
}
ITextBox.cs
namespace AbstractFactoryPatternExample.Product.TextBox
{
    public interface ITextBox
    {
        void Render();
    }
}
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 IButton or ITextBox interface. So, as per our requirements, let us create four concrete products, i.e., WindowButton, MacButton, WindowTextBox, and MacTextBox.

WindowButton.cs
namespace AbstractFactoryPatternExample.Product.Button
{
    public class WindowButton : IButton
    {
        public void Render()
        {
            Console.WriteLine("Render window button");
        }
    }
}
MacButton.cs
namespace AbstractFactoryPatternExample.Product.Button
{
    public class MacButton : IButton
    {
        public void Render()
        {
            Console.WriteLine("Render mac button");
        }
    }
}
WindowTextBox.cs
namespace AbstractFactoryPatternExample.Product.TextBox
{
    public class WindowTextBox:ITextBox
    {
        public void Render()
        {
            Console.WriteLine("Render window textbox");
        }
    }
}
MacTextBox.cs
namespace AbstractFactoryPatternExample.Product.TextBox
{
    public class MacTextBox:ITextBox
    {
        public void Render()
        {
            Console.WriteLine("Render mac textbox");
        }
    }
}
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 IUIFactory.So, create a interface file with the name IUIFactory.cs

IUIFactory.cs
using AbstractFactoryPatternExample.Product.Button;
using AbstractFactoryPatternExample.Product.TextBox;
namespace AbstractFactoryPatternExample.Factory
{
    public interface IUIFactory
    {
        IButton CreateButton();
        ITextBox CreateTextBox();
    }
}

As you can see, this interface contains two methods. The CreateButton method will create different variants of buttons, whereas the CreateTextBox method will create different variants of textbox.Remember, here we're just stating the methods and specifying that both methods return abstract products - namely, IButton and ITextbox.

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., WindowUIFactory and MacUIFactory.

WindowUIFactory.cs
using AbstractFactoryPatternExample.Product.Button;
using AbstractFactoryPatternExample.Product.TextBox;

namespace AbstractFactoryPatternExample.Factory
{
    public class WindowUIFactory : IUIFactory
    {
        public IButton CreateButton()
        {
            return new WindowButton();
        }

        public ITextBox CreateTextBox()
        {
            return new WindowTextBox();
        }
    }
}
MacUIFactory.cs
using AbstractFactoryPatternExample.Product.Button;
using AbstractFactoryPatternExample.Product.TextBox;

namespace AbstractFactoryPatternExample.Factory
{
    public class MacUIFactory : IUIFactory
    {
        public IButton CreateButton()
        {
            return new MacButton();
        }

        public ITextBox CreateTextBox()
        {
            return new MacTextBox();
        }
    }
}
Step 5: Client

The Client class uses AbstractFactory and AbstractProduct interfaces to create a family of related objects. The following example code is self-explained, so please go through the comment lines for a better understanding.

using AbstractFactoryPatternExample.Factory;
using AbstractFactoryPatternExample.Product.Button;
using AbstractFactoryPatternExample.Product.TextBox;

// Create Windows UI
IUIFactory factory = new WindowUIFactory(); 
IButton button = factory.CreateButton();
ITextBox textBox = factory.CreateTextBox();

button.Render(); // This will render the appropriate button for the chosen factory.
textBox.Render(); // This will render the appropriate text box.

Console.WriteLine("-----------------------------------------------");

// Create Mac UI
IUIFactory factory1 = new MacUIFactory();
IButton button1 = factory1.CreateButton();
ITextBox textBox1 = factory1.CreateTextBox();

button1.Render(); // This will render the appropriate button for the chosen factory.
textBox1.Render(); // This will render the appropriate text box.

Console.ReadLine();
Output

The Abstract Factory Design Pattern enables easy switching between different families of objects, like Windows and macOS UI, by merely changing the concrete factory. This flexibility and maintainability are advantageous, especially in complex systems with multiple platforms or variations.

In essence, this pattern facilitates the creation of related objects with a unified interface. It minimizes code dependency, making it easier to maintain, test, and expand your codebase. For systems with diverse platforms or variations, the Abstract Factory Pattern proves to be a valuable addition.

The full source code is available here:

Happy coding!! 😊

No comments:

Post a Comment

^ Scroll to Top