Python 中的设计模式
什么是 Python 中的设计模式?
设计模式是开发者实施的最佳实践。它们解决了软件开发阶段中出现的一般性问题。这些设计模式是经过一段时间的多轮试验和错误后发明的。
设计模式的不同类型有哪些?
- 创建型:我们以面向对象风格创建对象的方式。它应用于我们实例化类的方式中的模式。
- 结构型:我们的类和对象如何组合形成应用程序中更大的结构。
- 行为型:对象如何有效地交互而不紧密耦合。
设计模式
单例模式 Singleton Pattern
单例模式意味着一个类应该只有一个实例。通过遵循这种模式,我们可以避免为特定类创建多个实例。
单例模式的一个很好的例子是我们应用程序中的数据库连接。在应用程序中拥有多个数据库实例会使应用程序不稳定。
import pymongo
class DBInstance:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(DBInstance, cls).__new__(cls)
# 初始化数据库连接
url = "mongodb://localhost:27017"
db_name = "sample"
try:
client = pymongo.MongoClient(url)
cls._instance.db = client[db_name]
except Exception as e:
print("DB Error", e)
return cls._instance
@classmethod
def get_instance(cls):
if cls._instance is None:
return cls()
return cls._instance
抽象工厂模式 Abstract Factory Pattern
从简单工厂模式开始
为了简化说明,我给你一个类比。假设你饿了,想吃点东西。你可以自己做饭,也可以从餐厅点餐。在第二种方式中,你不需要学习或知道如何做饭就能吃到食物。
同样,工厂模式简单地为用户生成对象实例,而不向客户端暴露任何实例化逻辑。
扩展简单工厂示例
扩展我们的简单工厂示例,假设你饿了,决定从餐厅点餐。根据你的喜好,你可能会点不同的菜系。然后,你可能需要根据菜系选择最好的餐厅。
如你所见,你的食物和餐厅之间存在依赖关系。不同的餐厅适合不同的菜系。
使用抽象工厂模式的笔记本电脑商店
# 接口定义
class IProcessor:
def process(self):
pass
def attach_storage(self, storage):
pass
class IStorage:
def store(self):
pass
class ILaptopFactory:
def create_processor(self):
pass
def create_storage(self):
pass
# 具体实现类
class MacbookProcessor(IProcessor):
def __init__(self):
self.storage = None
def process(self):
print("Processing with Macbook processor")
def attach_storage(self, storage):
self.storage = storage
print("Storage attached to Macbook processor")
class MacbookStorage(IStorage):
def store(self):
print("Storing data in Macbook storage")
class LaptopFactory(ILaptopFactory):
def create_processor(self):
return MacbookProcessor()
def create_storage(self):
return MacbookStorage()
# 客户端代码
def build_laptop(laptop_factory):
processor = laptop_factory.create_processor()
storage = laptop_factory.create_storage()
processor.attach_storage(storage)
return processor
# 使用示例
factory = LaptopFactory()
laptop = build_laptop(factory)
建造者模式 Builder Pattern
建造者模式允许你创建不同风格的对象,而无需在类中使用构造函数。
class User:
def __init__(self, first_name=None, last_name=None, gender=None, age=None):
self.first_name = first_name
self.last_name = last_name
self.gender = gender
self.age = age
class UserBuilder:
def __init__(self):
self.first_name = None
self.last_name = None
self.gender = None
self.age = None
def set_first_name(self, first_name):
self.first_name = first_name
return self
def set_last_name(self, last_name):
self.last_name = last_name
return self
def set_gender(self, gender):
self.gender = gender
return self
def set_age(self, age):
self.age = age
return self
def get_all_values(self):
return {
"first_name": self.first_name,
"last_name": self.last_name,
"gender": self.gender,
"age": self.age
}
def build(self):
return User(
self.first_name,
self.last_name,
self.gender,
self.age
)
# 使用示例
user_builder = UserBuilder()
user_builder.set_first_name("John").set_last_name("Doe").set_gender("man").set_age(30)
print("getAllValues", user_builder.get_all_values()) # UserBuilder 实例的值
print("build", user_builder.build()) # User 实例
适配器模式 Adapter Pattern
适配器模式的一个经典例子是形状不同的电源插座。有时,插座和设备插头不匹配。为了确保它能工作,我们会使用适配器。这正是我们在适配器模式中要做的。
它是将不兼容的对象包装在适配器中以使其与另一个类兼容的过程。
# 接口定义
class IError:
def serialize(self):
pass
class INewError:
def serialize(self):
pass
# 具体实现类
class NewCustomerError(INewError):
def __init__(self, message):
self.message = message
def serialize(self):
return {
"error": {
"message": self.message,
"timestamp": "2023-01-01"
}
}
class CustomerError(IError):
def __init__(self, message):
self.message = message
def serialize(self):
return {
"message": self.message
}
# 适配器
class CustomerError_v2(INewError):
def __init__(self, message):
self.message = message
def serialize(self):
# 在未来替换为 NewCustomerError
return NewCustomerError(self.message).serialize()
观察者模式 Observer Pattern
观察者模式是当另一个对象的状态发生变化时更新依赖项的方式。它通常包含观察者(Observer)
和被观察者(Observable)
。观察者
订阅被观察者
,当有变化时,被观察者通知观察者。
from abc import ABC, abstractmethod
# 接口定义
class IObserver(ABC):
@abstractmethod
def update(self, tweet):
pass
class IObservable(ABC):
@abstractmethod
def subscribe(self, observer):
pass
@abstractmethod
def unsubscribe(self, observer):
pass
@abstractmethod
def notify(self, tweet):
pass
# 具体实现类
class Tweet:
def __init__(self, content, author):
self.content = content
self.author = author
class Author(IObservable):
def __init__(self):
self.followers = []
def subscribe(self, observer):
self.followers.append(observer)
def unsubscribe(self, observer):
self.followers.remove(observer)
def notify(self, tweet):
for follower in self.followers:
follower.update(tweet)
def send_tweet(self, tweet):
print(f"Author sent a tweet: {tweet.content}")
self.notify(tweet)
class Follower(IObserver):
def __init__(self, name):
self.name = name
def update(self, tweet):
print(f"{self.name} received tweet: {tweet.content} from {tweet.author}")
# 使用示例
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/activate', methods=['POST'])
def activate():
try:
follower1 = Follower("Ganesh")
follower2 = Follower("Doe")
author = Author()
author.subscribe(follower1)
author.subscribe(follower2)
author.send_tweet(Tweet("Welcome", "Bruce Lee"))
return jsonify({"success": True, "data": None}), 200
except Exception as e:
print(e)
return jsonify({"success": False, "data": None}), 500
if __name__ == '__main__':
app.run(port=4000)
策略模式 Strategy Pattern
策略模式允许你在运行时选择算法或策略。这种模式的真实用例是基于文件大小切换文件存储策略。
考虑你想在应用程序中根据文件大小处理文件存储:
from abc import ABC, abstractmethod
# 接口定义
class IFileWriter(ABC):
@abstractmethod
def write(self, path):
pass
# 具体策略实现
class DiskWriter(IFileWriter):
def write(self, path):
print(f"Writing file to disk at {path}")
class AWSWriterWrapper(IFileWriter):
def write(self, path):
print("Writing file to AWS S3")
# 上下文类
class Writer:
def __init__(self, strategy):
self.strategy = strategy
def write(self, path):
return self.strategy.write(path)
# 使用示例
size = 1000
if size < 1000:
writer = Writer(DiskWriter())
writer.write("file path comes here")
else:
writer = Writer(AWSWriterWrapper())
writer.write(None)
责任链模式 Chain of Responsibility Pattern
责任链模式允许对象通过一系列条件或功能链。它不是在一个地方管理所有功能和条件,而是将其拆分为对象必须通过的条件链。
from abc import ABC, abstractmethod
# 抽象处理器
class Handler(ABC):
def __init__(self):
self._next_handler = None
def set_next(self, handler):
self._next_handler = handler
return handler
@abstractmethod
def handle(self, request):
pass
# 具体处理器
class AuthenticationHandler(Handler):
def handle(self, request):
print("Authenticating request...")
if request.get("authenticated"):
print("Authentication successful")
if self._next_handler:
return self._next_handler.handle(request)
return True
else:
print("Authentication failed")
return False
class AuthorizationHandler(Handler):
def handle(self, request):
print("Authorizing request...")
if request.get("authorized"):
print("Authorization successful")
if self._next_handler:
return self._next_handler.handle(request)
return True
else:
print("Authorization failed")
return False
class ValidationHandler(Handler):
def handle(self, request):
print("Validating request...")
if request.get("valid"):
print("Validation successful")
if self._next_handler:
return self._next_handler.handle(request)
return True
else:
print("Validation failed")
return False
# 使用示例
def process_request(request):
# 创建责任链
authentication = AuthenticationHandler()
authorization = AuthorizationHandler()
validation = ValidationHandler()
# 设置链
authentication.set_next(authorization).set_next(validation)
# 处理请求
result = authentication.handle(request)
if result:
print("Request processed successfully")
else:
print("Request processing failed")
# 测试
valid_request = {
"authenticated": True,
"authorized": True,
"valid": True
}
invalid_request = {
"authenticated": True,
"authorized": False,
"valid": True
}
process_request(valid_request)
print("\n---\n")
process_request(invalid_request)
外观模式 Facade Pattern
外观模式为复杂的子系统提供了一个简化的接口。它隐藏了系统的复杂性,并提供了一个客户端可以访问系统的接口。
# 复杂子系统组件
class CPU:
def freeze(self):
print("CPU: Freezing...")
def jump(self, position):
print(f"CPU: Jumping to position {position}")
def execute(self):
print("CPU: Executing commands")
class Memory:
def load(self, position, data):
print(f"Memory: Loading data '{data}' to position {position}")
class HardDrive:
def read(self, sector, size):
print(f"HardDrive: Reading {size} bytes from sector {sector}")
return "data from hard drive"
# 外观
class ComputerFacade:
def __init__(self):
self.cpu = CPU()
self.memory = Memory()
self.hard_drive = HardDrive()
def start(self):
self.cpu.freeze()
self.memory.load(0, self.hard_drive.read(0, 1024))
self.cpu.jump(0)
self.cpu.execute()
# 客户端代码
computer = ComputerFacade()
computer.start()
状态模式 State Pattern
例子:红绿灯变化
State: "red" | "green" | "yellow" method: onChange
from abc import ABC, abstractmethod
# 状态接口
class State(ABC):
@abstractmethod
def handle(self, context):
pass
# 具体状态
class ConcreteStateA(State):
def handle(self, context):
print("Handling request in State A")
context.state = ConcreteStateB()
class ConcreteStateB(State):
def handle(self, context):
print("Handling request in State B")
context.state = ConcreteStateA()
# 上下文
class Context:
def __init__(self):
self.state = ConcreteStateA()
def request(self):
self.state.handle(self)
# 使用示例
context = Context()
context.request() # 输出: Handling request in State A
context.request() # 输出: Handling request in State B
context.request() # 输出: Handling request in State A
Python 中的反模式
过度使用 Any
类型
在 Python 中,虽然它是动态类型语言,但我们可以使用类型提示。过度使用Any
类型(在 Python 中相当于不使用类型提示)会导致类型安全性问题。
# 不好的做法
def process_data(data: Any) -> Any:
return data + 10
# 更好的做法
def process_data(data: int) -> int:
return data + 10
类复杂性
类实例化
过于复杂的类实例化可能导致代码难以理解和维护。
# 复杂的类实例化
class ComplexClass:
def __init__(self, a, b, c, d, e, f, g, h):
self.a = a
self.b = b
self.c = c
self.d = d
self.e = e
self.f = f
self.g = g
self.h = h
# 使用建造者模式简化
class ComplexClassBuilder:
def __init__(self):
self.a = None
self.b = None
# ...
def with_a(self, a):
self.a = a
return self
# ...
def build(self):
return ComplexClass(self.a, self.b, self.c, self.d, self.e, self.f, self.g, self.h)
定义对象字面量
在 Python 中,对象字面量(字典)是非常常见的,但过度复杂的嵌套字典可能导致代码难以理解。
# 复杂的嵌套字典
config = {
"server": {
"host": "localhost",
"port": 8080,
"settings": {
"timeout": 30,
"retry": {
"count": 3,
"delay": 5
}
}
}
}
# 更好的做法:使用类来结构化数据
class RetryConfig:
def __init__(self, count=3, delay=5):
self.count = count
self.delay = delay
class ServerSettings:
def __init__(self, timeout=30, retry=None):
self.timeout = timeout
self.retry = retry or RetryConfig()
class ServerConfig:
def __init__(self, host="localhost", port=8080, settings=None):
self.host = host
self.port = port
self.settings = settings or ServerSettings()
config = ServerConfig()
使用 Function
类型
在 Python 中,函数是一等公民,可以作为参数传递。但过度使用函数类型可能导致代码难以理解。
# 过度使用函数类型
def apply_operation(data, operation):
return operation(data)
# 更好的做法:使用策略模式
from abc import ABC, abstractmethod
class Operation(ABC):
@abstractmethod
def apply(self, data):
pass
class AddOperation(Operation):
def __init__(self, value):
self.value = value
def apply(self, data):
return data + self.value
class MultiplyOperation(Operation):
def __init__(self, value):
self.value = value
def apply(self, data):
return data * self.value
def apply_operation(data, operation):
return operation.apply(data)
结论
我们已经了解了应用程序开发中常用的设计模式。在软件开发中还有许多其他可用的设计模式。
设计模式提供了解决常见问题的经过验证的解决方案。通过学习和应用这些模式,我们可以编写更加健壮、可维护和可扩展的代码。
然而,重要的是要记住,设计模式不是万能的解决方案。我们应该根据具体问题选择合适的模式,而不是强行应用模式。过度设计可能导致代码复杂性增加,反而降低了可维护性。
在 Python 中,由于语言的动态特性和灵活性,某些设计模式的实现可能与静态类型语言(如 Java 或 TypeScript)有所不同。我们应该利用 Python 的优势,同时遵循良好的设计原则。
资源
- Python 设计模式指南: https://python-patterns.guide/
- Python 中的设计模式: https://refactoring.guru/design-patterns/python