5.设计模式

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 包已停止维护,找不到了~

往年同期文章