Skip to main content

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 的优势,同时遵循良好的设计原则。

资源