RO EN

Factory Method – flexible object creation without knowing the exact class

Factory Method – flexible object creation without knowing the exact class
Doru Bulubasa
03 November 2025

One of the most useful design patterns in the Creational Patterns category is the Factory Method.

This pattern allows us to create objects without specifying exactly which class will be instantiated, providing an elegant way to extend code without modifying it.


🧩 What is Factory Method

In object-oriented programming, we often need to create objects from a family of similar types.

Directly using new for each concrete type makes the code rigid and difficult to extend.

Factory Method offers an elegant solution: it defines an interface or an abstract class that declares a method for creating objects, and subclasses decide which concrete type will be instantiated.

The goal is simple: separating the object creation code from the code that uses them.


⚙️ Practical example in C#

Imagine a simple scenario: we want to build a notification system that can send messages via Email or SMS.

Without Factory Method, the code would look like this:

public class NotificationService
{
    public void Send(string type, string message)
    {
        if (type == "email")
            new EmailNotifier().Notify(message);
        else if (type == "sms")
            new SmsNotifier().Notify(message);
    }
}

The problem?

If we want to add a new notification type (e.g., Push), we have to modify the existing code — which contradicts the Open/Closed principle (Open for extension, closed for modification).


🏗️ Correct implementation with Factory Method

We apply Factory Method to delegate the creation process of the notifier to a derived class:

public abstract class NotificationFactory
{
    public abstract INotifier CreateNotifier();
}

public class EmailNotificationFactory : NotificationFactory
{
    public override INotifier CreateNotifier() => new EmailNotifier();
}

public class SmsNotificationFactory : NotificationFactory
{
    public override INotifier CreateNotifier() => new SmsNotifier();
}

Common interface:

public interface INotifier
{
    void Notify(string message);
}

public class EmailNotifier : INotifier
{
    public void Notify(string message) =>
        Console.WriteLine($"📧 Email: {message}");
}

public class SmsNotifier : INotifier
{
    public void Notify(string message) =>
        Console.WriteLine($"📱 SMS: {message}");
}

Usage:

NotificationFactory factory = new EmailNotificationFactory();
var notifier = factory.CreateNotifier();
notifier.Notify("Message sent via Factory Method!");

If we want to change the notification type, we only change the factory, not the application logic.


💡 Advantages of Factory Method

Extensibility – we can add new object types without modifying existing code.

Clear separation between creation logic and usage.

Applicable in testing – we can inject mock factories to simulate behaviors.

Adheres to SOLID principles, especially Open/Closed and Single Responsibility.


⚠️ When to avoid Factory Method

Although elegant, Factory Method can unnecessarily complicate code for simple scenarios.

If you have only one or two concrete classes and do not plan extensions, direct instantiation with new may be sufficient.

However, as the application grows, Factory Method becomes essential for scalable and maintainable architectures.


🧠 Factory Method vs Abstract Factory

Factory Method is often confused with the Abstract Factory.

The difference is that Factory Method deals with creating a single product, while Abstract Factory produces families of compatible objects (we will discuss this pattern in a future article).


🚀 Conclusion

Factory Method is a cornerstone of object-oriented architecture.

It provides an elegant way to create objects without depending on their concrete classes, allowing code to be easy to extend, test, and maintain.

In the .NET world, this pattern is commonly found in frameworks such as ASP.NET, Blazor, or Entity Framework, where factories manage services, components, and dynamic objects.