Card 04/ 09

ExampleDifficulty: Intermediate2 min

Factory Method Example: A Notification Sender per Channel

The order code sends a notification; each channel's subclass decides whether it is an email or an SMS.

An order system that sends shipping notices is a natural Factory Method, and this example maps the template onto it. It tells customers their order has shipped, by email for some and by SMS for others. The message and the moment it is sent are the same for both. The only difference is which kind of sender is created, which is exactly the decision the pattern hands to a subclass.

Template participants and the classes that play them
ParticipantClass in this example
ProductSender, with one method send(text)
ConcreteProductEmailSender and SmsSender
CreatorOrderNotifier, whose notify_shipped calls the factory method
ConcreteCreatorEmailOrderNotifier and SmsOrderNotifier
Factory methodcreate_sender
py
from abc import ABC, abstractmethod


class Sender(ABC):
    @abstractmethod
    def send(self, text: str) -> str: ...


class EmailSender(Sender):
    def send(self, text: str) -> str:
        return f"email to [email protected]: {text}"


class SmsSender(Sender):
    def send(self, text: str) -> str:
        return f"SMS to +44 7700 900123: {text}"


class OrderNotifier(ABC):
    @abstractmethod
    def create_sender(self) -> Sender: ...

    def notify_shipped(self, order_id: str) -> None:
        sender = self.create_sender()
        print(sender.send(f"Order {order_id} has shipped and will arrive in two days."))


class EmailOrderNotifier(OrderNotifier):
    def create_sender(self) -> Sender:
        return EmailSender()


class SmsOrderNotifier(OrderNotifier):
    def create_sender(self) -> Sender:
        return SmsSender()


EmailOrderNotifier().notify_shipped("A-1042")
SmsOrderNotifier().notify_shipped("A-1042")
OutputRan with python:3.12-slim (Python 3.12.13)
email to [email protected]: Order A-1042 has shipped and will arrive in two days.
SMS to +44 7700 900123: Order A-1042 has shipped and will arrive in two days.
`notify_shipped` is written once, and each subclass decides the sender.

notify_shipped builds the message and sends it, and it does not know which channel it is using. Adding push notifications later means a PushSender and a PushOrderNotifier, and no edit to the code that already sends email and SMS.

The creator has a domain name, OrderNotifier, not a pattern name. That is typical, and it is why the pattern is often missed in real code: you recognise it by the shape, an overridable method that returns an object through an interface, rather than by a class called Factory.