Python教程40:常用设计模式

“不要重复造轮子。”

设计模式是解决常见问题的可复用方案。今天我们学习Python中常用的设计模式,提升代码设计能力。

1. 创建型模式

单例模式(Singleton)

确保类只有一个实例:

 1class Singleton:
 2    _instance = None
 3    
 4    def __new__(cls):
 5        if cls._instance is None:
 6            cls._instance = super().__new__(cls)
 7        return cls._instance
 8
 9# 或使用装饰器
10def singleton(cls):
11    instances = {}
12    def get_instance(*args, **kwargs):
13        if cls not in instances:
14            instances[cls] = cls(*args, **kwargs)
15        return instances[cls]
16    return get_instance
17
18@singleton
19class Database:
20    def __init__(self, url):
21        self.url = url

工厂模式(Factory)

根据条件创建不同对象:

 1class ShapeFactory:
 2    @staticmethod
 3    def create_shape(shape_type):
 4        if shape_type == "circle":
 5            return Circle()
 6        elif shape_type == "rectangle":
 7            return Rectangle()
 8        else:
 9            raise ValueError(f"未知形状:{shape_type}")
10
11# 使用
12shape = ShapeFactory.create_shape("circle")

建造者模式(Builder)

分步骤构建复杂对象:

 1class QueryBuilder:
 2    def __init__(self):
 3        self._select = []
 4        self._from = None
 5        self._where = []
 6    
 7    def select(self, *fields):
 8        self._select.extend(fields)
 9        return self
10    
11    def from_table(self, table):
12        self._from = table
13        return self
14    
15    def where(self, condition):
16        self._where.append(condition)
17        return self
18    
19    def build(self):
20        query = f"SELECT {', '.join(self._select)}"
21        query += f" FROM {self._from}"
22        if self._where:
23            query += f" WHERE {' AND '.join(self._where)}"
24        return query
25
26# 使用(链式调用)
27sql = (QueryBuilder()
28       .select("name", "age")
29       .from_table("users")
30       .where("age > 18")
31       .build())

2. 结构型模式

适配器模式(Adapter)

使不兼容的接口协同工作:

 1class OldAPI:
 2    def old_method(self, data):
 3        return f"Old: {data}"
 4
 5class NewAPI:
 6    def new_method(self, data):
 7        return f"New: {data}"
 8
 9class Adapter:
10    """适配器:将OldAPI适配到NewAPI接口"""
11    def __init__(self, old_api):
12        self.old_api = old_api
13    
14    def new_method(self, data):
15        # 调用旧接口,返回新接口格式
16        return self.old_api.old_method(data)
17
18# 使用
19old = OldAPI()
20adapted = Adapter(old)
21print(adapted.new_method("test"))

装饰器模式(Decorator)

动态添加功能:

 1class Coffee:
 2    def cost(self):
 3        return 5
 4
 5    def description(self):
 6        return "Coffee"
 7
 8class MilkDecorator:
 9    """装饰器:添加牛奶"""
10    def __init__(self, coffee):
11        self._coffee = coffee
12    
13    def cost(self):
14        return self._coffee.cost() + 2
15    
16    def description(self):
17        return self._coffee.description() + ", Milk"
18
19# 使用
20coffee = Coffee()
21print(coffee.cost(), coffee.description())
22
23with_milk = MilkDecorator(coffee)
24print(with_milk.cost(), with_milk.description())

3. 行为型模式

观察者模式(Observer)

对象间一对多的依赖关系:

 1class Subject:
 2    """被观察者"""
 3    def __init__(self):
 4        self._observers = []
 5    
 6    def attach(self, observer):
 7        self._observers.append(observer)
 8    
 9    def notify(self, message):
10        for observer in self._observers:
11            observer.update(message)
12
13class Observer:
14    """观察者"""
15    def __init__(self, name):
16        self.name = name
17    
18    def update(self, message):
19        print(f"{self.name}收到:{message}")
20
21# 使用
22subject = Subject()
23obs1 = Observer("观察者1")
24obs2 = Observer("观察者2")
25
26subject.attach(obs1)
27subject.attach(obs2)
28subject.notify("事件发生")

策略模式(Strategy)

定义一系列算法,让它们可互换:

 1class PaymentStrategy:
 2    def pay(self, amount):
 3        pass
 4
 5class CreditCard(PaymentStrategy):
 6    def pay(self, amount):
 7        return f"用信用卡支付${amount}"
 8
 9class PayPal(PaymentStrategy):
10    def pay(self, amount):
11        return f"用PayPal支付${amount}"
12
13class ShoppingCart:
14    def __init__(self, payment_strategy):
15        self.payment_strategy = payment_strategy
16    
17    def checkout(self, amount):
18        return self.payment_strategy.pay(amount)
19
20# 使用
21cart = ShoppingCart(CreditCard())
22print(cart.checkout(100))
23
24cart.payment_strategy = PayPal()  # 切换策略
25print(cart.checkout(100))

命令模式(Command)

将请求封装为对象:

 1class Command:
 2    def execute(self):
 3        pass
 4
 5class LightOnCommand(Command):
 6    def __init__(self, light):
 7        self.light = light
 8    
 9    def execute(self):
10        self.light.turn_on()
11
12class Light:
13    def turn_on(self):
14        print("灯打开")
15
16class RemoteControl:
17    def __init__(self):
18        self.command = None
19    
20    def set_command(self, command):
21        self.command = command
22    
23    def press_button(self):
24        self.command.execute()
25
26# 使用
27light = Light()
28command = LightOnCommand(light)
29remote = RemoteControl()
30remote.set_command(command)
31remote.press_button()

4. Python特色模式

上下文管理器模式

 1class FileManager:
 2    def __init__(self, filename):
 3        self.filename = filename
 4    
 5    def __enter__(self):
 6        self.file = open(self.filename)
 7        return self.file
 8    
 9    def __exit__(self, *args):
10        self.file.close()
11
12with FileManager("file.txt") as f:
13    content = f.read()

迭代器模式

 1class Range:
 2    def __init__(self, start, end):
 3        self.start = start
 4        self.end = end
 5    
 6    def __iter__(self):
 7        return RangeIterator(self.start, self.end)
 8
 9class RangeIterator:
10    def __init__(self, start, end):
11        self.current = start
12        self.end = end
13    
14    def __next__(self):
15        if self.current >= self.end:
16            raise StopIteration
17        value = self.current
18        self.current += 1
19        return value
20
21for i in Range(0, 5):
22    print(i)

5. 小结

设计模式分类:

创建型:单例、工厂、建造者 结构型:适配器、装饰器 行为型:观察者、策略、命令 Python特色:上下文管理器、迭代器

选择合适的模式能提升代码质量和可维护性。


练习题

  1. 实现一个线程安全的单例模式
  2. 用策略模式实现不同的排序算法
  3. 实现一个简单的发布-订阅系统(观察者模式)

本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读