Saturday, June 27, 2026

Factory Method Design Pattern

Part 2.2 – Factory Method Design Pattern

Series: Design Patterns in C# and ASP.NET Core

Pattern Type: Creational Design Pattern

Difficulty: ⭐⭐☆☆☆ (Beginner to Intermediate)

Prerequisites: OOP Concepts, Interfaces, Inheritance, Polymorphism


Table of Contents

  1. Introduction

  2. What is Factory Method Pattern?

  3. Why Do We Need Factory Method?

  4. The Problem with new

  5. Real-World Analogy

  6. Factory Method Structure

  7. UML Class Diagram

  8. Components of the Pattern

  9. Step-by-Step C# Example

  10. ASP.NET Core Example

  11. Real-World Use Cases

  12. Advantages

  13. Disadvantages

  14. Factory Method vs Simple Factory

  15. Best Practices

  16. Common Mistakes

  17. Interview Questions

  18. Summary


Introduction

One of the most common practices among beginner developers is creating objects directly using the new keyword.

Payment payment = new CreditCardPayment();

At first glance, this looks perfectly fine. However, as applications grow, direct object creation introduces tight coupling, making the system harder to maintain, extend, and test.

Imagine an e-commerce application that initially supports only Credit Card payments. Later, business requirements change, and the application must support PayPal, UPI, Net Banking, and Cryptocurrency payments.

If every part of the application directly creates payment objects using new, every location must be updated when a new payment type is introduced. This increases maintenance effort and the risk of bugs.

The Factory Method Pattern addresses this by separating object creation from object usage.


What is the Factory Method Pattern?

Definition

The Factory Method Pattern defines an interface (or abstract method) for creating objects, allowing subclasses or specialized factory classes to decide which concrete object to instantiate.

In simple terms, instead of creating objects directly, you ask a factory to create them.

Instead of writing:

new CreditCardPayment();

you write:

factory.CreatePayment();

The client no longer needs to know the concrete class being created.


Why Do We Need the Factory Method Pattern?

Without the Factory Method Pattern:

  • Business logic is tightly coupled to concrete classes.

  • Adding new implementations requires modifying existing code.

  • Testing becomes more difficult because dependencies are hard-coded.

  • The application violates the Open/Closed Principle (OCP).

With the Factory Method Pattern:

  • Object creation is centralized.

  • New implementations can be added with minimal changes.

  • Client code depends on abstractions rather than concrete implementations.

  • The system becomes easier to maintain and extend.


The Problem with new

Consider an online shopping application.

public class PaymentProcessor
{
    public void Process()
    {
        CreditCardPayment payment = new CreditCardPayment();
        payment.Pay();
    }
}

The PaymentProcessor is directly dependent on CreditCardPayment.

If support for PayPal is added, the class must be modified:

public void Process(string type)
{
    if(type == "Card")
        new CreditCardPayment();

    else if(type == "PayPal")
        new PaypalPayment();

    else if(type == "UPI")
        new UpiPayment();
}

This approach quickly becomes cluttered and difficult to maintain.


Real-World Analogy

Imagine ordering coffee at a café.

You don't walk into the kitchen and prepare the coffee yourself.

Instead, you tell the barista what you want.

The barista decides:

  • Which ingredients to use.

  • Which machine to operate.

  • How the coffee is prepared.

You simply receive the finished coffee.

In this analogy:

  • Customer → Client

  • Barista → Factory

  • Coffee → Product

The customer doesn't know how the coffee is made—they only request a type of coffee.


Factory Method Structure

The pattern consists of four main participants:

  • Product – Defines the interface.

  • Concrete Product – Implements the product.

  • Creator (Factory) – Declares the factory method.

  • Concrete Creator – Implements the factory method to return a specific product.


UML Class Diagram

                   +----------------------+
                   |      IPayment        |
                   +----------------------+
                   | + Pay()             |
                   +----------^-----------+
                              |
        +---------------------+---------------------+
        |                                           |
+----------------------+                 +----------------------+
| CreditCardPayment    |                 | PaypalPayment        |
+----------------------+                 +----------------------+
| + Pay()             |                 | + Pay()             |
+----------------------+                 +----------------------+

                    +----------------------+
                    | PaymentFactory       |
                    +----------------------+
                    | + CreatePayment()    |
                    +----------^-----------+
                               |
        +----------------------+----------------------+
        |                                             |
+------------------------+              +------------------------+
| CreditCardFactory      |              | PaypalFactory          |
+------------------------+              +------------------------+
| CreatePayment()        |              | CreatePayment()        |
+------------------------+              +------------------------+

Components of the Pattern

Product

Defines the common interface.

public interface IPayment
{
    void Pay(decimal amount);
}

Concrete Products

public class CreditCardPayment : IPayment
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paid ₹{amount} using Credit Card.");
    }
}

public class PaypalPayment : IPayment
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paid ₹{amount} using PayPal.");
    }
}

Creator (Factory)

public abstract class PaymentFactory
{
    public abstract IPayment CreatePayment();
}

Concrete Factories

public class CreditCardFactory : PaymentFactory
{
    public override IPayment CreatePayment()
    {
        return new CreditCardPayment();
    }
}

public class PaypalFactory : PaymentFactory
{
    public override IPayment CreatePayment()
    {
        return new PaypalPayment();
    }
}

Step-by-Step C# Example

Client Code

class Program
{
    static void Main()
    {
        PaymentFactory factory = new CreditCardFactory();

        IPayment payment = factory.CreatePayment();

        payment.Pay(2500);
    }
}

Output

Paid ₹2500 using Credit Card.

If you want to switch to PayPal:

PaymentFactory factory = new PaypalFactory();

No other client code changes are required.


ASP.NET Core Example

In ASP.NET Core, the Factory Method Pattern is often combined with Dependency Injection.

Product Interface

public interface INotificationService
{
    void Send(string message);
}

Concrete Products

public class EmailNotificationService : INotificationService
{
    public void Send(string message)
    {
        Console.WriteLine($"Email: {message}");
    }
}

public class SmsNotificationService : INotificationService
{
    public void Send(string message)
    {
        Console.WriteLine($"SMS: {message}");
    }
}

Factory

public interface INotificationFactory
{
    INotificationService Create(string notificationType);
}

public class NotificationFactory : INotificationFactory
{
    public INotificationService Create(string notificationType)
    {
        return notificationType switch
        {
            "Email" => new EmailNotificationService(),
            "SMS" => new SmsNotificationService(),
            _ => throw new ArgumentException("Unsupported notification type")
        };
    }
}

Register Services

builder.Services.AddSingleton<INotificationFactory, NotificationFactory>();

Controller

public class NotificationController : ControllerBase
{
    private readonly INotificationFactory _factory;

    public NotificationController(INotificationFactory factory)
    {
        _factory = factory;
    }

    [HttpPost]
    public IActionResult Send(string type, string message)
    {
        var service = _factory.Create(type);
        service.Send(message);

        return Ok();
    }
}

Real-World Use Cases

The Factory Method Pattern is commonly used when the exact type of object depends on runtime conditions.

Examples include:

  • Payment gateways (Credit Card, UPI, PayPal, Stripe)

  • Notification systems (Email, SMS, Push)

  • Document generators (PDF, Excel, Word)

  • Database providers (SQL Server, PostgreSQL, MySQL)

  • Cloud storage providers (Azure Blob Storage, AWS S3, Google Cloud Storage)

  • Report exporters (CSV, PDF, Excel)


Advantages

  • Promotes loose coupling by depending on abstractions.

  • Supports the Open/Closed Principle.

  • Centralizes object creation logic.

  • Makes testing easier by allowing mock implementations.

  • Simplifies adding new product types without changing client code.

  • Encourages cleaner and more maintainable code.


Disadvantages

  • Introduces additional classes, increasing the size of the codebase.

  • Can feel excessive for very small or simple applications.

  • Requires developers to understand abstraction and inheritance.

  • Poorly designed factories can become overly complex.


Factory Method vs Simple Factory

FeatureSimple FactoryFactory Method
Standard GoF Pattern❌ No✅ Yes
Uses Inheritance❌ Usually not✅ Yes
Uses PolymorphismLimitedExtensive
ExtensibleLimitedHigh
Open/Closed PrincipleOften violated when adding new productsBetter supported
ComplexityLowerHigher
Best ForSmall applicationsMedium to large applications

Simple Factory centralizes creation in a single class, often using if or switch statements. It's straightforward but can require modification when new product types are added.

Factory Method relies on inheritance and polymorphism. New product types are introduced by creating new factory subclasses rather than modifying existing factory logic, aligning better with the Open/Closed Principle.


Best Practices

  • Program to interfaces, not concrete implementations.

  • Keep factories focused on object creation only.

  • Avoid placing business logic inside factories.

  • Use Dependency Injection to supply factories where appropriate.

  • Consider the Abstract Factory Pattern when multiple related objects must be created together.


Common Mistakes

Overusing the Pattern

Not every object needs a factory. For simple data objects or classes with trivial construction, using new directly is often perfectly acceptable.

Mixing Business Logic into Factories

Factories should create objects, not perform business operations.

Returning Concrete Types

Return interfaces or abstract base classes from factory methods whenever possible. This keeps client code decoupled from specific implementations.


Interview Questions

1. What is the Factory Method Pattern?

It is a creational design pattern that defines an interface for creating objects while allowing subclasses or specialized factories to determine which concrete object to instantiate.


2. What problem does the Factory Method Pattern solve?

It removes direct dependencies on concrete classes, making code more maintainable, extensible, and testable.


3. How does the Factory Method Pattern support the Open/Closed Principle?

New product types can be introduced by adding new concrete factories and products without modifying existing client code.


4. What is the difference between Factory Method and Abstract Factory?

Factory Method creates one product through a factory method. Abstract Factory creates families of related products using a factory interface with multiple creation methods.


5. What is the difference between Factory Method and Simple Factory?

A Simple Factory usually uses conditional logic in one class to create products. Factory Method uses inheritance and polymorphism, making it easier to extend without modifying existing code.


6. Where is the Factory Method Pattern commonly used?

  • Payment processing

  • Notification services

  • Database provider selection

  • Report generation

  • Cloud storage integration

  • Plugin architectures


Summary

The Factory Method Pattern is a foundational creational design pattern that separates object creation from object usage. By introducing factories and programming to interfaces, it reduces coupling, improves extensibility, and aligns with SOLID principles—particularly the Open/Closed Principle and Dependency Inversion Principle.

While direct use of new is appropriate in many simple scenarios, Factory Method becomes valuable when object creation depends on runtime conditions, configuration, or evolving business requirements. Combined with ASP.NET Core's Dependency Injection framework, it enables flexible, testable, and maintainable application architectures.


Coming Up Next

In Part 2.3, we'll explore the Abstract Factory Design Pattern, including:

  • What is the Abstract Factory Pattern?

  • Factory Method vs. Abstract Factory

  • Creating families of related objects

  • UML Class Diagram

  • Complete C# Console Application

  • ASP.NET Core implementation

  • Real-world examples

  • Advantages and disadvantages

  • Common mistakes

  • Interview questions and best practices

You'll see how Abstract Factory builds upon Factory Method to create entire groups of related objects while maintaining consistency across product families.

Abstract-factory-design-pattern


No comments:

Don't Copy

Protected by Copyscape Online Plagiarism Checker