Factory Pattern in .NET: A Beginner’s Guide to Object Creation

Factory Pattern in .NET: Beginner’s Guide to Object Creation

Learn how to implement the Factory Pattern in .NET for efficient object creation. This beginner-friendly guide covers concepts, examples, and best practices.


Introduction

Imagine you're developing a .NET application that needs to create different types of objects dynamically. Without a structured approach, you might end up writing repetitive code, violating the Single Responsibility Principle and making future modifications harder.

This is where the Factory Pattern comes in. The Factory Pattern is a creational design pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created.

In this article, we’ll break down the Factory Pattern in .NET, why it's useful, how to implement it, and best practices to follow.


What is the Factory Pattern?

The Factory Pattern is a design pattern used for creating objects without exposing the instantiation logic to the client. It provides a common interface for object creation and delegates the responsibility to derived classes.

Benefits of the Factory Pattern

  • Encapsulates Object Creation – Keeps object creation logic separate from the main business logic.
  • Supports Loose Coupling – Reduces dependencies between components.
  • Enhances Maintainability – Makes it easier to modify object creation logic in one place.
  • Promotes Code Reusability – Helps reuse object creation logic across multiple classes.
  • Follows Open/Closed Principle – Enables adding new object types without modifying existing code.

Implementing the Factory Pattern in .NET

1. Without the Factory Pattern (The Problem)

Consider a pizza ordering system where we create different pizza types manually:

public class Pizza {
    public string Type { get; set; }
    public Pizza(string type) {
        Type = type;
    }
}

public class PizzaStore {
    public Pizza OrderPizza(string type) {
        if (type == "Cheese") {
            return new Pizza("Cheese");
        } else if (type == "Pepperoni") {
            return new Pizza("Pepperoni");
        }
        return null;
    }
}

Issues:

  • Hardcoded logic for object creation.
  • Difficult to add new pizza types.
  • Violates Open/Closed Principle.

2. Implementing the Factory Pattern

Step 1: Create an Interface

public interface IPizza {
    void Prepare();
}

Step 2: Create Concrete Classes

public class CheesePizza : IPizza {
    public void Prepare() {
        Console.WriteLine("Preparing Cheese Pizza");
    }
}

public class PepperoniPizza : IPizza {
    public void Prepare() {
        Console.WriteLine("Preparing Pepperoni Pizza");
    }
}

Step 3: Implement the Factory Class

public class PizzaFactory {
    public static IPizza CreatePizza(string type) {
        return type switch {
            "Cheese" => new CheesePizza(),
            "Pepperoni" => new PepperoniPizza(),
            _ => throw new ArgumentException("Invalid pizza type")
        };
    }
}

Step 4: Use the Factory in the Application

class Program {
    static void Main() {
        IPizza pizza = PizzaFactory.CreatePizza("Cheese");
        pizza.Prepare();
    }
}

Now, when we need to add a new pizza type, we simply create a new class and modify the factory, making our code more maintainable and scalable.


Advanced Factory Pattern Techniques

1. Factory Method Pattern

Instead of a static factory class, we can use an abstract class with a factory method.

public abstract class PizzaFactory {
    public abstract IPizza CreatePizza();
}

public class CheesePizzaFactory : PizzaFactory {
    public override IPizza CreatePizza() => new CheesePizza();
}

public class PepperoniPizzaFactory : PizzaFactory {
    public override IPizza CreatePizza() => new PepperoniPizza();
}

Usage:

var factory = new CheesePizzaFactory();
IPizza pizza = factory.CreatePizza();
pizza.Prepare();

2. Dependency Injection with Factory Pattern

To decouple the factory from client code, we can integrate it with Dependency Injection (DI).

Register Factory in DI Container (ASP.NET Core)

builder.Services.AddTransient<PizzaFactory>();

Inject Factory in Controller

[ApiController]
[Route("api/pizza")]
public class PizzaController : ControllerBase {
    private readonly PizzaFactory _pizzaFactory;

    public PizzaController(PizzaFactory pizzaFactory) {
        _pizzaFactory = pizzaFactory;
    }

    [HttpGet("order")]
    public IActionResult OrderPizza(string type) {
        var pizza = _pizzaFactory.CreatePizza(type);
        pizza.Prepare();
        return Ok("Pizza Ordered");
    }
}

Best Practices for Using the Factory Pattern

  • Use interfaces or abstract classes for better flexibility.
  • Avoid overcomplicating small projects; use the Factory Pattern only when needed.
  • Integrate Dependency Injection to make factories more reusable.
  • Use configuration-driven factories for dynamic object creation.
  • Keep Factory classes lightweight and single-purpose.

Conclusion

The Factory Pattern is a powerful tool in .NET for creating objects efficiently while following best coding practices. It helps in reducing tight coupling, improving maintainability, and making the code scalable.

By implementing Factory Methods, integrating Dependency Injection, and following best practices, you can ensure a robust and flexible architecture for your .NET applications.

Start using the Factory Pattern today and experience cleaner, more maintainable code!


FAQs

1. When should I use the Factory Pattern?

Use it when object creation logic is complex, repetitive, or requires abstraction.

2. What is the difference between Factory Pattern and Dependency Injection?

Factory Pattern creates objects on demand, while Dependency Injection manages object lifetimes and dependencies.

3. Can I use Factory Pattern in ASP.NET Core?

Yes! You can register factories as services in DI containers to keep object creation flexible and decoupled.

4. Is the Factory Pattern the same as the Singleton Pattern?

No. The Factory Pattern creates multiple instances, while the Singleton Pattern ensures only one instance exists.


Found this guide helpful? Share it with your network and subscribe for more .NET tips!

Sandip Mhaske

I’m a software developer exploring the depths of .NET, AWS, Angular, React, and digital entrepreneurship. Here, I decode complex problems, share insightful solutions, and navigate the evolving landscape of tech and finance.

Post a Comment

Previous Post Next Post