How to Implement Factory Method Pattern in C

This article provides a practical overview of implementing the Factory Method design pattern in C#. You will learn the core concept behind this creational pattern, examine its primary architectural components, walk through a clean code implementation using a real-world scenario, and understand the key scenarios where applying this pattern is beneficial.

What is the Factory Method Pattern?

The Factory Method is a creational design pattern that defines an interface or abstract class for creating an object, but allows subclasses to decide which class to instantiate. It promotes loose coupling by eliminating the need to bind application-specific classes into your code, adhering closely to the Open/Closed Principle and the Single Responsibility Principle.

Core Components

The pattern consists of four main participants:

  1. Product Interface (IProduct): Defines the common interface for objects the factory method creates.
  2. Concrete Products (ConcreteProductA, ConcreteProductB): Specific implementations of the product interface.
  3. Creator (Creator): Declares the factory method that returns new product instances. It can also provide default business logic that relies on the product.
  4. Concrete Creators (ConcreteCreatorA, ConcreteCreatorB): Overrides the factory method to return an instance of a specific concrete product.

Step-by-Step Implementation in C

The following example demonstrates a logistics application where goods are delivered either by truck or by ship.

1. Define the Product Interface

public interface ITransport
{
    string Deliver();
}

2. Create Concrete Products

public class Truck : ITransport
{
    public string Deliver()
    {
        return "Delivering cargo overland in a box truck.";
    }
}

public class Ship : ITransport
{
    public string Deliver()
    {
        return "Delivering cargo by sea in a container ship.";
    }
}

3. Define the Creator Abstract Class

The creator defines the abstract factory method CreateTransport(). It may also contain core business logic that operates on the product returned by this method.

public abstract class Logistics
{
    // The Factory Method
    public abstract ITransport CreateTransport();

    // Core business logic relying on the Factory Method
    public string PlanDelivery()
    {
        ITransport transport = CreateTransport();
        return $"Logistics: {transport.Deliver()}";
    }
}

4. Implement Concrete Creators

Each concrete creator instantiates and returns its respective concrete product.

public class RoadLogistics : Logistics
{
    public override ITransport CreateTransport()
    {
        return new Truck();
    }
}

public class SeaLogistics : Logistics
{
    public override ITransport CreateTransport()
    {
        return new Ship();
    }
}

5. Client Usage

The client interacts with the creator via its base class interface, remaining agnostic of the concrete types being created.

class Program
{
    static void Main(string[] args)
    {
        Logistics roadLogistics = new RoadLogistics();
        Console.WriteLine(roadLogistics.PlanDelivery());
        // Output: Logistics: Delivering cargo overland in a box truck.

        Logistics seaLogistics = new SeaLogistics();
        Console.WriteLine(seaLogistics.PlanDelivery());
        // Output: Logistics: Delivering cargo by sea in a container ship.
    }
}

When to Use the Factory Method

  • Unknown Dependencies: Use the pattern when you do not know beforehand the exact types and dependencies of the objects your code will work with.
  • Extensibility: Use it when you want to provide users of your library or framework with a way to extend its internal components.
  • Decoupling: Use it to isolate object creation logic from your core business logic, making unit testing and maintenance easier.