Factory pattern: centralise object creation

The caller asks a factory for an interface. The factory chooses which concrete object to create, keeping construction decisions in one place.

Time O(1) selectionSpace one object per creationCode C++, Python and C#
Watch it animatedStep through it, with the running line highlighted. Free with an account.

The idea

The factory owns the decision about which notifier class to instantiate. The caller works with INotifier and does not need a switch or direct construction scattered across the application.

Code

class Notifier {
public:
    virtual string send(const string& message) = 0;
    virtual ~Notifier() = default;
};
class EmailNotifier : public Notifier {
public:
    string send(const string& message) override { return "Email: " + message; }
};
class SmsNotifier : public Notifier {
public:
    string send(const string& message) override { return "SMS: " + message; }
};
unique_ptr<Notifier> createNotifier(const string& channel) {
    if (channel == "email") return make_unique<EmailNotifier>();
    if (channel == "sms") return make_unique<SmsNotifier>();
    throw invalid_argument("unknown channel");
}

int main() {
    unique_ptr<Notifier> notifier = createNotifier("email");
    cout << notifier->send("Order shipped") << "\n";
}
from typing import Protocol

class Notifier(Protocol):
    def send(self, message: str) -> str: ...

class EmailNotifier:
    def send(self, message: str) -> str: return "Email: " + message

class SmsNotifier:
    def send(self, message: str) -> str: return "SMS: " + message

def create_notifier(channel: str) -> Notifier:
    match channel:
        case "email": return EmailNotifier()
        case "sms": return SmsNotifier()
        case _: raise ValueError(channel)

notifier = create_notifier("email")
print(notifier.send("Order shipped"))
interface INotifier {
    string Send(string message);
}
class EmailNotifier : INotifier {
    public string Send(string message) => "Email: " + message;
}
class SmsNotifier : INotifier {
    public string Send(string message) => "SMS: " + message;
}
static class NotifierFactory {
    public static INotifier Create(string channel) => channel switch {
        "email" => new EmailNotifier(),
        "sms" => new SmsNotifier(),
        _ => throw new ArgumentOutOfRangeException(nameof(channel))
    };
}

INotifier notifier = NotifierFactory.Create("email");
Console.WriteLine(notifier.Send("Order shipped"));

Tips

In the .NET library

A dependency-injection container can act as a factory too. Use a custom factory when creation needs runtime input, such as the selected notification channel.