C# Factory Method

Summary: in this tutorial, you’ll learn about the C# factory method design pattern and how to use it to create objects without tightly coupling the object creation code to the client code.

Introduction to the C# factory method design pattern

A real-world factory produces products. In programming, a factory creates objects. When a method creates and returns an object, it is called a factory method.

The Factory Method pattern is a creational design pattern, which provides an interface for creating objects in a superclass but allows subclasses to decide the object type.

The following UML diagram illustrates the Factory Method pattern:

C# factory method design pattern

The Factory Method pattern consists of the following participants:

  • Creator: the abstract class that defines a factory method for creating objects. The creator can be an interface if it doesn’t have a shared implementation with the subclasses.
  • Product: the abstract class that defines the interface for the objects created by the factory method. Like the Creator, the Product can be an interface.
  • ConcreteFactory: the concrete class that inherits from the Creator class. The ConcreteFactory class creates ConcreateProduct that inherits from the Product.
  • ConcreteProduct: the concrete class that extends the Product class.

Here’s the implementation of the factory method pattern in C#:

namespace FactoryMethod;

public abstract class Product {}

public abstract class Creator
{
    public abstract Product FactoryMethod();

    public void Operation()
    {
        var product = FactoryMethod();
        
        // process the product
        // ...
        Console.WriteLine($"Work with the {product}");
    }
}

public class ConcreateProduct: Product {}

public class ConcreteFactory : Creator
{
    public override Product FactoryMethod() => new ConcreateProduct();
}

public class Program
{
    public static void Main(string[] args)
    {
        var creator = new ConcreteCreator();
        creator.Operation();
    }
}Code language: C# (cs)

Output:

Work with the FactoryMethod.ConcreateProductCode language: JavaScript (javascript)

Factory method pattern vs. the new keyword

1) The new keyword creates dependencies between the client code and the concrete implementations of classes

When you use the new keyword to create objects of classes, you create dependencies between the client code and the concrete implementation of the classes.

If the classes change, you must change the client code to accommodate the new implementation. This makes your code tightly coupled and difficult to extend.

The Factory Method pattern decouples the client code from the implementation of the objects.

The client code only needs to know the factory interface, which provides a way to create objects without knowing the specific implementation of the objects it creates.

Therefore, the factory method makes your code more flexible, testable, and easier to extend.

2) The new keyword makes it difficult to swap out implementations

The new keyword also makes it difficult to swap out implementations. If you introduce a new implementation or replace an existing one, you must the client code, violating the open-closed principle.

On the other hand, using the Factory Method makes it easier to swap out implementations without modifying the client code.

The reason is that the client code only needs to know the factory interface and can use it to create objects without knowing the specific implementation.

C# Factory Method design pattern example

The following program demonstrates how to use the Factory Method pattern to implement a discount policy for a simplified order system:

namespace FactoryMethod;

public abstract class Discount
{
    public abstract decimal GetPercentage();
}
public class RegularDiscount : Discount
{
    public override decimal GetPercentage() => 0.1m;
}
public class IrregularDiscount : Discount
{
    public override decimal GetPercentage() => 0.15m;
}

public abstract class DiscountPolicy
{
    public abstract Discount Create();

    public decimal Apply(decimal Price)
    {
        var discount = Create();
        return Price * (1 - discount.GetPercentage());
    }

}

public class RegularDiscountPolicy : DiscountPolicy
{
    public override Discount Create() => new RegularDiscount();
}


public class IrregularDiscountPolicy : DiscountPolicy
{
    public override Discount Create() => new IrregularDiscount();
}

public class Order
{
    private readonly decimal _netAmount;
    public decimal Amount => OrderDiscountPolicy.Apply(_netAmount);
    public DiscountPolicy OrderDiscountPolicy
    {
        get; private set;
    }
    public Order(decimal amount, DiscountPolicy discountPolicy)
    {
        _netAmount = amount;
        OrderDiscountPolicy = discountPolicy;
    }
}

public class Program
{
    public static void Main()
    {
        var order = new Order(1000, new IrregularDiscountPolicy());
        Console.WriteLine(order.Amount);
    }
}Code language: C# (cs)

Output:

850.00Code language: CSS (css)

How it works.

The following UML diagram illustrates how the relationships between classes in the program:

C# factory method design pattern example

First, define the DiscountPolicy as an abstract class. The DiscountPolicy class use the Create() method that creates and returns a new Discount object.

Next, define the RegularDiscountPolicy and IrregularDiscountPolicy classes that extend the DiscountPolicy class. The Create() method of these classes returns a RegularDiscount and IrregularDiscount object, respectively.

Then, define the Discount class as an abstract class. The Discount class has two concrete classes including RegularDiscount and IrregularDiscount classes.

After that, define the Order class that uses the DiscountPolicy class. The Order class stores a net amount of the order and a discount policy. The Amount property returns the amount after applying the discount policy to the net amount.

Finally, create an Order object with a net amount of 1000 and an IrregularDiscountPolicy object in the Main() method of the Program class and displays the amount after applying the discount policy to the console.

In this example, you can swap the discount policy from the IrregularDiscountPolicy to RegularDiscountPolicy without modifying the Order class.

Also, you can introduce a new discount policy e.g., SpecialDiscountPolicy and swap it with the current discount policy without changing the Order class.

Summary

  • Use the Factory Method design pattern to create objects without tightly coupling the object creation code to the client code.
Was this tutorial helpful ?