1 建议 50:利用模块实现单例模式
单例模式可以保证系统中一个类只有一个实例。
模块采用的其实是天然的单例的实现方式:
- 所有的变量都会绑定到模块
- 模块只初始化一次
- import 机制是线程安全的
创建一个 world 单例:
# World.py
import Sun
def run():
while True:
Sun.rise()
Sun.set()
# main.py
import World
World.run()
2 建议 51:用 mixin 模式让程序更加灵活
每个类都有一个 __bases__
属性,它是一个元组,用来存放所有的基类
Python 语言中的基类在运行中可以动态改变,也就是所谓的混入(mixin)
def simple_tea_people():
people = People()
people.__bases__ += (UseSimpleTeapot, )
return people
def coffee_people():
people = People()
people.__bases__ += (UseCoffeepot, )
return people
def tea_and_coffee_people():
people = People()
people.__bases__ += (UseSimpleTeapot, UseCoffeepot, )
return people
3 建议 52:用发布订阅模式实现松耦合
发布/订阅模式(publish/subscribe 或 pub/sub)是一种编程模式,
- 发布者将发布的消息分为不同的类别直接发布,不会关注订阅者是谁
- 订阅者通过订阅一个或多个类别,只接收感兴趣的消息,不关注发布者是谁
- 发布者和订阅者之间一个中间代理人(Broker),维持这种发布/订阅关系
- 发布/订阅模式最大的优点是实现了发布者与订阅者之间的松耦合
Blinker
模块支持一对一、一对多的订阅发布模式,内核小巧但功能强大。
模块python-message
则支持更多丰富的特性,不过本人未找到准确的文档说明,目前活跃的messages
包与书中描述不一致,时过境迁呢~
具体可参考blinker文档和messages文档(存疑)
4 建议 53:用状态模式美化代码
状态模式是一种行为设计模式,在该模式中,一个对象可以基于其内部状态封装多个行为。比如根据收音机的基本状态(AM/FM),当调谐到 AM 或 FM 频道时,扫描频道的行为就会相应地发生动态的改变。
状态模式示例:
from abc import abstractmethod, ABCMeta
class State(metaclass=ABCMeta):
@abstractmethod
def handle(self):
pass
class ConcreteStateB(State):
def handle(self):
print("ConcreteStateB")
class ConcreteStateA(State):
def handle(self):
print("ConcreteStateA")
class Context(State):
def __init__(self):
self.state = None
def getState(self):
return self.state
def setState(self, state):
self.state = state
def handle(self):
self.state.handle()
context = Context()
stateA = ConcreteStateA()
stateB = ConcreteStateB()
context.setState(stateA)
context.handle()
状态模式的优点
- 在状态设计模式中,对象的行为是其状态的函数结果,且行为在运行时依据状态而改变。这消除了程序对 if/else 或 switch/case 条件逻辑的依赖
- 使用状态模式,实现多态行为是很方便的,并且易于添加状态来支持额外的行为
- 状态模式提高了聚合性,针对状态的行为被分别放置在各自的 ConcreteState 类中
- 状态模式不仅改善了扩展应用程序行为时的灵活性,且提高了代码的可维护性。
状态模式的缺点
- 类爆炸:由于每个状态都需要创建一个对应的 ConcreteState 类,可能导致创建太多功能较为单一的类。既增加了代码量,又使得状态机的结构更加难以审查
- 随着新行为的引入,Context 类需要进行相应的更新以处理每个行为,使得上下文行为更容易受到每个新行为的影响
本小节内容参考自# Python 设计模式——状态模式
原书中提及的python-state
包已停止维护,找不到了~