设计模式概述
设计模式(GOF,即 Gang of Four,四人组提出的经典设计模式)是面向对象系统中对重要且重复出现的设计进行系统化总结的方案。它包含模式名称、问题、解决方法和效果这四个基本要素,有助于开发者更高效地设计和构建软件系统。
设计模式的基础
- 对象/类:面向对象编程的三大特性——封装、继承和多态是设计模式的基石。封装将数据和操作封装在一起,继承允许子类继承父类的属性和方法,多态则使得不同的对象可以对同一消息做出不同的响应。
- 接口:接口是一种特殊的类,规定了继承它的类必须实现的方法。在 Python 中,有两种常见的实现方式:
- 使用
NotImplementedError
:通过在基类方法中抛出NotImplementedError
异常,强制子类实现该方法。 - 使用
abc
模块:利用ABCMeta
元类和@abstractmethod
装饰器,明确声明抽象方法,使类成为抽象基类。
- 使用
设计模式的六大原则
- 开闭原则:软件实体应该对扩展开放,对修改关闭。这意味着在不修改现有代码的情况下,能够通过扩展来添加新的功能。
- 里氏替换原则:所有引用基类的方法必须能够透明地使用其子类的对象。即子类可以替换父类,而不会影响程序的正确性。
- 依赖倒置原则:高层模块不应依赖低层模块,二者都应依赖于抽象。通过依赖抽象,可以降低模块之间的耦合度。
- 接口隔离原则:使用多个专门的接口,而不是单一的总接口。这样可以避免类实现不必要的方法,提高代码的内聚性。
- 迪米特法则:软件实体应尽可能少地与其他实体发生相互作用,以降低耦合度。
- 单一职责原则:一个类应该只有一个导致其变更的原因。每个类应该只负责一项职责,提高代码的可维护性。
创建型模式
单例模式
- 定义:确保一个类只有一个实例,并提供一个全局访问点。
- 适用场景:当类只能有一个实例,并且需要全局访问时,如配置管理类、日志记录器等。
- 优点:对唯一实例的受控访问,避免命名空间污染。
- 示例代码:
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
# 测试单例模式
obj1 = Singleton()
obj2 = Singleton()
print(obj1 is obj2) # 输出: True
简单工厂模式
- 定义:通过一个工厂类负责创建产品类的实例,而不直接向客户端暴露对象创建的实现细节。
- 优点:隐藏了对象创建的实现细节,客户端无需修改代码。
- 缺点:违反单一职责原则,添加新产品时需修改工厂类代码。
- 示例代码:
from abc import abstractmethod, ABCMeta
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
class Alipay(Payment):
def pay(self, money):
print(f'支付宝支付 {money} 元')
class PaymentFactory:
def create_payment(self, method):
if method == 'alipay':
return Alipay()
else:
raise ValueError(f'未知支付方式: {method}')
factory = PaymentFactory()
payment = factory.create_payment('alipay')
payment.pay(100)
工厂方法模式
- 定义:定义一个用于创建对象的接口,让子类决定实例化哪一个产品类。
- 适用场景:需要生产多种复杂对象时,降低耦合度。
- 示例代码:
from abc import abstractmethod, ABCMeta
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
class Alipay(Payment):
def pay(self, money):
print(f'支付宝支付 {money} 元')
class PaymentFactory(metaclass=ABCMeta):
@abstractmethod
def create_payment(self):
pass
class AlipayFactory(PaymentFactory):
def create_payment(self):
return Alipay()
factory = AlipayFactory()
payment = factory.create_payment()
payment.pay(100)
抽象工厂模式
- 定义:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
- 适用场景:系统要独立于产品创建与组合时。
- 示例代码:
from abc import abstractmethod, ABCMeta
class PhoneShell(metaclass=ABCMeta):
@abstractmethod
def get_shell_info(self):
pass
class MiPhoneShell(PhoneShell):
def get_shell_info(self):
return '小米手机壳'
class PhoneFactory(metaclass=ABCMeta):
@abstractmethod
def make_shell(self):
pass
class MiFactory(PhoneFactory):
def make_shell(self):
return MiPhoneShell()
factory = MiFactory()
shell = factory.make_shell()
print(shell.get_shell_info())
建造者模式
- 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
- 适用场景:当创建复杂对象的算法应独立于该对象的组成部分时。
- 示例代码:
class Player:
def __init__(self, face=None, body=None):
self.face = face
self.body = body
def __str__(self):
return f'Player with {self.face} face and {self.body} body'
class PlayerBuilder:
def build_face(self):
pass
def build_body(self):
pass
def get_player(self):
pass
class BeautifulWomanBuilder(PlayerBuilder):
def build_face(self):
return '漂亮脸蛋'
def build_body(self):
return '苗条身材'
def get_player(self):
face = self.build_face()
body = self.build_body()
return Player(face, body)
builder = BeautifulWomanBuilder()
player = builder.get_player()
print(player)
原型模式
- 定义:通过复制现有对象来创建新对象,而不是通过实例化类。
- 适用场景:当创建对象的成本较高,或者需要创建多个相似对象时。
- 示例代码:
import copy
class Prototype:
def clone(self):
return copy.deepcopy(self)
class ConcretePrototype(Prototype):
def __init__(self, value):
self.value = value
def __str__(self):
return str(self.value)
# 创建原型对象
prototype = ConcretePrototype(10)
# 克隆对象
clone = prototype.clone()
print(prototype) # 输出: 10
print(clone) # 输出: 10
创建型模式小结
使用抽象工厂、原型或建造者模式的设计通常比工厂方法模式更灵活,但也更复杂。设计者通常从工厂方法开始,随着需求的变化,逐步演化到其他创建模式。了解多种模式可以为设计提供更多选择,根据具体的应用场景选择合适的设计模式,能够提高软件的可维护性、可扩展性和可复用性。