很多人觉得设计模式是Java那帮人搞的那套,跟Python没什么关系。Python太灵活了,什么模式好像都能用几行代码糊弄过去。这话对也不对。糊弄是可以糊弄,用是能用,但写出来的代码好不好改,别人看了骂不骂娘,那又是另一回事。
我挑了6个最常见的模式,用Python重写一遍。不整那些虚头巴脑的UML图,直接看代码。看完你大概会觉得,这些模式在Python里不但不违和,甚至能写得比Java更清爽。
1. 单例模式:别再用模块全局变量了
很多Python新手实现单例,直接在模块里写个全局变量。这确实能工作,但不够干净。真正的单例要控制类的实例化过程。
用__new__方法是最Pythonic的写法。每次实例化时都判断有没有创建过实例。
class Database: _instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._init_db()
return cls._instance
def _init_db(self):
self.connection = '连接成功'
db1 = Database()
db2 = Database()
print(db1 is db2) True
这样写的好处是,调用方根本不用知道自己拿的是单例。该new就new,底层替你管好了。
2. 工厂模式:别再用大段if-else了
工厂模式最怕写成俄罗斯套娃式的if-else。Python的好处是类本身就是对象,可以直接放在字典里。
class Dog: def speak(self): return '汪汪'
class Cat:
def speak(self): return '喵喵'
class AnimalFactory:
_animals = {
'dog': Dog,
'cat': Cat
}
@staticmethod
def create_animal(animal_type):
animal_class = AnimalFactory._animals.get(animal_type)
if not animal_class:
raise ValueError(f'不认识这个动物: {animal_type}')
return animal_class()
animal = AnimalFactory.create_animal('dog')
每次加新动物类型,只需要往字典里加一项。不用改核心代码,新来的同事看了直接笑出声。
3. 观察者模式:别用回调地狱了
Python的观察者模式其实很自然,因为函数和类方法都是可调用的。把观察者存成列表,事件触发时一个一个调。
class WeatherStation: def __init__(self):
self._observers = []
def register(self, observer):
self._observers.append(observer)
def notify(self, data):
for observer in self._observers:
observer.update(data)
class DisplayScreen:
def update(self, data):
print(f'温度变了: {data['temperature']}度')
station = WeatherStation()
screen = DisplayScreen()
station.register(screen)
station.notify({'temperature': 25})
你要是想省事,甚至可以直接传lambda进去。Python的灵活性让这个模式变得特别轻。
4. 策略模式:别再用switch-case了
策略模式本质是“把算法封装成对象”。Python里最直接的方式就是把函数当策略用。
def quick_sort(data): return sorted(data)
def bubble_sort(data):
for i in range(len(data)):
for j in range(0, len(data)-i-1):
if data[j] > data[j+1]:
data[j], data[j+1] = data[j+1], data[j]
return data
class Sorter:
def __init__(self, strategy=quick_sort):
self.strategy = strategy
def sort(self, data):
return self.strategy(data)
sorter = Sorter(bubble_sort)
print(sorter.sort([3, 1, 2]))
你甚至可以写个字典映射,让用户直接输字符串选策略。用起来灵活,改起来也方便。
5. 装饰器模式:Python原生就支持
其他语言要实现装饰器,得写嵌套类。Python直接有语法糖,太舒服了。
def log_decorator(func): def wrapper(args, kwargs):
print(f'调用方法: {func.__name__}')
result = func(args, kwargs)
print(f'返回结果: {result}')
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
add(1, 2)
输出: 调用方法: add
输出: 返回结果: 3
这个模式在Python里太常用,以至于很多新手都没意识到这是个设计模式。你写Flask、Django的时候,天天都在用。
6. 代理模式:懒加载和权限控制
代理模式就是给真实对象加个替身。比如一个很重的资源,等到真正用的时候才加载。
class HeavyResource: def load(self):
print('加载了100M数据')
return 'heavy data'
class Proxy:
def __init__(self):
self._resource = None
def load(self):
if self._resource is None:
self._resource = HeavyResource().load()
return self._resource
proxy = Proxy()
print(proxy.load()) 真正加载
print(proxy.load()) 直接返回缓存
Python的上下文管理器也可以当代理用。不过这个写法更直白,新人也看得懂。
这6个模式,每个都在解决一个具体问题。单例管实例,工厂管创建,观察者管通知,策略管算法,装饰器管增强,代理管控制。没有一个是虚无缥缈的。
试着把代码跑一遍,改一改。你会发现这些模式其实就是些套路,谁都能学会。写Python的人掌握了这些东西,写出来的代码会好维护很多。改bug的时候你就知道当初值不值得了。