Understanding Factory Design Pattern

Introduction

In this article, we will cover the Factory Design Pattern.

So, Let's get started.

Please refer to my previous article on Design Patterns,

SOLID Principles

Other Design Patterns

What is a Factory?

The Factory Design Pattern is a creational pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created. This pattern promotes loose coupling by eliminating the need to bind application-specific classes into the code.

Real-World Example. Designing a System for a Bank

Suppose you’re designing a bank system that supports various accounts: Savings, Current, and Fixed Deposit. Using the Factory Design Pattern, we can create a specific account type based on the user’s choice or requirements.

// Define the Product Interface
public interface IAccount
{
    decimal Balance { get; }
    void Deposit(decimal amount);
    void Withdraw(decimal amount);
}
//Concrete Implementations for the Products
public class SavingsAccount : IAccount
{
    public decimal Balance { get; private set; }
    public void Deposit(decimal amount)
    {
       Balance += amount;
       Console.WriteLine($"Deposited {amount} to Savings Account. New Balance: {Balance}");
    }
    
    public void Withdraw(decimal amount)
    { 
        // Implement logic specific to Savings account (e.g., limited withdrawals, minimum balance requirement)
        Balance -= amount;
        Console.WriteLine($"Withdrew {amount} from Savings Account. New Balance: {Balance}");
    }
}
public class CurrentAccount : IAccount
{
    public decimal Balance { get; private set; }
    public void Deposit(decimal amount)
    {
        Balance += amount;
        Console.WriteLine($"Deposited {amount} to Current Account. New Balance: {Balance}");
    }
     
    public void Withdraw(decimal amount)
    {
        // Implement logic specific to Current account (e.g., no withdrawal limit)
        Balance -= amount;
        Console.WriteLine($"Withdrew {amount} from Current Account. New Balance: {Balance}");
    }
}
public class FixedDepositAccount : IAccount
{
    public decimal Balance { get; private set; }
    public void Deposit(decimal amount)
    {
        // Typically, you can't deposit into a fixed deposit account once it's created. For simplicity, we'll allow it here.
        Balance += amount;
        Console.WriteLine($"Deposited {amount} to Fixed Deposit Account. New Balance: {Balance}");
    }
   
    public void Withdraw(decimal amount)
    {
        // Implement logic specific to Fixed Deposit account (e.g., penalties for early withdrawal)
        Balance -= amount;
        Console.WriteLine($"Withdrew {amount} from Fixed Deposit Account with penalty. New Balance: {Balance}");
    }
}
//Factory Class to Produce the Products
public static class AccountFactory
{
    public static IAccount CreateAccount(string accountType)
    {
        switch (accountType.ToLower())
        {
            case "savings":
                return new SavingsAccount();
            case "current":
                return new CurrentAccount();
            case "fixeddeposit":
                return new FixedDepositAccount();
            default:
                throw new ArgumentException("Invalid account type");
        }
    }
}
// Testing the Factory Design Pattern

public class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Enter the type of account you'd like to create (savings, current, fixeddeposit): ");
        string accountType = Console.ReadLine();
     
        try
        {
            IAccount account = AccountFactory.CreateAccount(accountType);
            account.Deposit(1000);   // Sample operation to show account creation.
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine(ex.Message);
        }
     
        Console.ReadKey();      
    }
}

Outputs

Savings Output

Current Output

Factory design pattern

Why Use Factory?

  • Encapsulation: Hides the instantiation logic.
  • Flexibility: Makes it easier to introduce new types of objects.
  • Decoupling: Reduces dependency on concrete classes.
  • Maintainability: Simplifies the maintenance and extension of the codebase.

Where to Use Factory?

  • When the exact type of object to create is not known until runtime.
  • When you want to centralize the creation logic of objects.
  • When you need to manage and maintain a group of related subclasses.

Summary

In this article, I have tried to cover Factory Design Patterns.

Up Next
    Ebook Download
    View all
    Learn
    View all