The factory decides which notifier to build; the service is the code that uses it. By taking a factory as a constructor argument, NotificationService never names a concrete notifier class. It just asks the factory. This is the payoff of the pattern: the dispatch logic is written once and works for every channel, present or future.
Build NotificationService:
If the channel is unknown, the ValueError from the factory should propagate naturally. Do not catch it.
class Notifier:
def send(self, message):
raise NotImplementedError
class EmailNotifier(Notifier):
def send(self, message):
return {"channel": "email", "message": message}
class SmsNotifier(Notifier):
def send(self, message):
return {"channel": "sms", "message": message}
class PushNotifier(Notifier):
def send(self, message):
return {"channel": "push", "message": message}
def notifier_for(channel):
if channel == "email":
return EmailNotifier()
if channel == "sms":
return SmsNotifier()
if channel == "push":
return PushNotifier()
raise ValueError("unknown channel: " + str(channel))
class NotifierFactory:
def __init__(self):
self._registry = {}
def register(self, channel, cls):
self._registry[channel] = cls
def create(self, channel):
if channel not in self._registry:
raise ValueError("unknown channel: " + str(channel))
return self._registry[channel]()
class NotificationService:
def __init__(self, factory):
self._factory = factory
def notify(self, channel, message):
"""Build a notifier via the factory and return its send result."""
# TODO: hand the channel to self._factory so it builds the notifier for
# you, then give back exactly what that notifier produces when asked to
# send the message. An unknown channel's ValueError should escape here
# uncaught, so do not wrap this in error handling.
pass
The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.
The factory decides which notifier to build; the service is the code that uses it. By taking a factory as a constructor argument, NotificationService never names a concrete notifier class. It just asks the factory. This is the payoff of the pattern: the dispatch logic is written once and works for every channel, present or future.
Build NotificationService:
If the channel is unknown, the ValueError from the factory should propagate naturally. Do not catch it.
Press Run Tests or ββ© to check your solution.