7. 综合练习:可插拔的通知中心
这是什么:一个约 70 行的通知中心——发布一条公告,开启的渠道(短信、邮件)自动收到格式化后的消息。它把前六章的四个模式串进一个真实小项目。
为什么用:散着学的模式容易忘;在一个项目里亲眼看到"工厂管创建、策略管格式、观察者管通知、单例管配置"各司其职,模式才真正变成你的手感。
如何用:按"渠道 → 格式 → 组装"三步搭出来,最后整段运行,再做扩展挑战。
第一步:工厂造渠道,单例管配置
渠道类只管发,工厂表按名字造,配置中心(单例)决定哪些渠道开启:
# ---------- 工厂:渠道 ----------
class SmsChannel:
def push(self, text):
print(f"[短信] {text}")
class MailChannel:
def push(self, text):
print(f"[邮件] {text}")
CHANNELS = {"sms": SmsChannel, "mail": MailChannel} # 加渠道?这里加一行
def create_channel(name):
return CHANNELS[name]()
# ---------- 单例:配置中心 ----------
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.enabled = ["sms", "mail"] # 开启哪些渠道
return cls._instance
CHANNELS 是第 2 章的工厂表,Config 是第 2 章的 __new__ 单例——"可插拔"的第一层:渠道随便加,只动工厂表和配置。
第二步:策略定格式
同一条公告,群发要短、存档要全——格式做成策略,按名字换:
# ---------- 策略:消息格式 ----------
def brief(event):
return f"{event['title']}!"
def detail(event):
return f"{event['title']}({event['detail']})"
FORMATS = {"brief": brief, "detail": detail}
第 6 章的策略字典原样搬来。
第三步:观察者组装中心
通知中心持有渠道列表(被通知方名单),发布时用当前策略格式化、逐渠道推送:
# ---------- 观察者思想:中心发布,渠道接收 ----------
class NotificationCenter:
def __init__(self):
config = Config() # 全局唯一配置
self.channels = [create_channel(n) for n in config.enabled]
self.format = FORMATS["brief"] # 默认简洁格式
def use_format(self, name): # 换格式 = 换策略
self.format = FORMATS[name]
def publish(self, event): # 发布:逐渠道通知
text = self.format(event)
for ch in self.channels:
ch.push(text)
# ---------- 跑起来 ----------
center = NotificationCenter()
event = {"title": "服务器上线", "detail": "2 号机 10:00 部署完成"}
center.publish(event) # 默认简洁格式
center.use_format("detail") # 切成详细格式
center.publish(event)
你会看到:
[短信] 服务器上线!
[邮件] 服务器上线!
[短信] 服务器上线(2 号机 10:00 部署完成)
[邮件] 服务器上线(2 号机 10:00 部署完成)
四个模式各司其职
| 模式 | 在项目里的岗位 | 来自 |
|---|---|---|
| 工厂 | CHANNELS 表按名字造渠道 |
第 2 章 |
| 单例 | Config 全局唯一,决定开哪些渠道 |
第 2 章 |
| 策略 | FORMATS 表按名字换格式 |
第 6 章 |
| 观察者 | 中心发布,名单上的渠道逐个收到 | 第 6 章 |
记忆口诀
配置单例管开关,工厂照名单造渠道;策略定格式,中心来广播——四处解耦,随时插拔。
动手改(扩展挑战)
- 加一个钉钉渠道:写
DingChannel类、CHANNELS表加一行、Config.enabled加"ding",三处各一行,其他代码零改动——体验"可插拔" - 加一个
urgent策略:格式为【加急】{title}({detail}),切换后重新发布 - 给
NotificationCenter加unsubscribe(channel)方法,发布前退订邮件渠道,验证只收短信