Python 中常见设计模式的教程:聚焦于继承、多态与行为模式

欢迎来到这个教程!我们将基于面向对象编程(OOP)的核心概念(如继承、多态),探讨几个常见的类似设计模式。这些模式常用于处理可变行为、接口一致性和系统扩展,比如你之前的通知系统设计(使用抽象基类实现多态)。教程将从基础解释开始,逐步深入到代码实现和实际应用。

我会用Python示例,因为它简单且支持抽象基类(ABC)。假设你有基本的Python知识(如类、继承)。每个模式后,我会比较它与你设计的相似性,并给出优化建议。

1. 准备工作:理解核心OOP概念

  • 继承(Inheritance):子类从父类(或基类)获取属性和方法。用于代码复用,但过度使用可能导致紧耦合。
  • 多态(Polymorphism):同一方法名在不同类中实现不同行为。通过基类引用调用子类方法。
  • 抽象基类(ABC):使用from abc import ABC, abstractmethod定义接口,强制子类实现抽象方法。

示例基础代码(你的通知系统简化版):

from abc import ABC, abstractmethod

class NotificationBot(ABC):
    @abstractmethod
    def send_message(self, message):
        pass

class EmailBot(NotificationBot):
    def send_message(self, message):
        print(f"发送邮件: {message}")

class SmsBot(NotificationBot):
    def send_message(self, message):
        print(f"发送短信: {message}")

# 多态使用
def notify(bot: NotificationBot, msg: str):
    bot.send_message(msg)

notify(EmailBot(), "Hello!")  # 输出: 发送邮件: Hello!

这展示了继承(EmailBot/SmsBot 继承 NotificationBot)和多态(notify 函数统一调用)。

2. 策略模式(Strategy Pattern)

解释

策略模式将算法或行为封装成独立类,通过上下文类动态选择。适合当行为需要运行时切换时(如通知系统切换平台)。

  • 为什么用?:避免if-else分支,提高灵活性。
  • 组件:策略接口(抽象基类)、具体策略(子类)、上下文(使用策略的类)。

与你设计的相似性

你的NotificationBot就是策略接口,send_message是行为。相似,但策略模式更强调动态注入(e.g., setter方法)。

代码实现

from abc import ABC, abstractmethod

# 策略接口
class SortStrategy(ABC):
    @abstractmethod
    def sort(self, data):
        pass

# 具体策略
class BubbleSort(SortStrategy):
    def sort(self, data):
        return sorted(data)  # 简化实现

class QuickSort(SortStrategy):
    def sort(self, data):
        return sorted(data, reverse=True)  # 简化

# 上下文
class Sorter:
    def __init__(self, strategy: SortStrategy):
        self.strategy = strategy

    def set_strategy(self, strategy: SortStrategy):
        self.strategy = strategy  # 动态切换

    def perform_sort(self, data):
        return self.strategy.sort(data)

# 使用
sorter = Sorter(BubbleSort())
print(sorter.perform_sort([3, 1, 2]))  # [1, 2, 3]
sorter.set_strategy(QuickSort())
print(sorter.perform_sort([3, 1, 2]))  # [3, 2, 1]

应用场景

  • 支付系统:策略为支付宝/微信。
  • 优化你的设计:添加setter到NotificationBot,实现动态切换平台。

3. 模板方法模式(Template Method Pattern)

解释

基类定义算法骨架(固定步骤),子类实现可变部分。适合流程固定但细节变的情况。

  • 为什么用?:确保核心流程一致,同时允许自定义。
  • 组件:抽象基类(定义模板方法)、钩子方法(抽象,子类实现)。

与你设计的相似性

你的抽象方法send_message像钩子。如果添加通用步骤(如日志记录),就更像模板方法。

代码实现

from abc import ABC, abstractmethod

class Game(ABC):
    def play(self):  # 模板方法:固定流程
        self.initialize()
        self.start()
        self.end()

    @abstractmethod
    def initialize(self):
        pass

    @abstractmethod
    def start(self):
        pass

    @abstractmethod
    def end(self):
        pass

class Chess(Game):
    def initialize(self):
        print("设置棋盘")

    def start(self):
        print("开始下棋")

    def end(self):
        print("游戏结束")

# 使用
Chess().play()
# 输出:
# 设置棋盘
# 开始下棋
# 游戏结束

应用场景

  • 报告生成:基类定义“加载数据 -> 处理 -> 输出”,子类自定义处理。
  • 优化你的设计:在NotificationBot添加模板如def notify(self, msg): self.log(); self.send_message(msg);,子类只实现send_message。

4. 桥接模式(Bridge Pattern)

解释

分离抽象和实现,使用组合(has-a)而非继承。适合多维度变化(如形状+颜色)。

  • 为什么用?:避免继承爆炸,提高独立扩展。
  • 组件:抽象(接口)、实现(独立接口)、桥接(抽象持有实现)。

与你设计的相似性

你的设计用继承;桥接用组合,更灵活。如果你的Bot有多个变体(如协议+平台),桥接更好。

代码实现

from abc import ABC, abstractmethod

# 实现接口
class Color(ABC):
    @abstractmethod
    def fill(self):
        pass

class Red(Color):
    def fill(self):
        return "红色"

class Blue(Color):
    def fill(self):
        return "蓝色"

# 抽象接口(桥接)
class Shape(ABC):
    def __init__(self, color: Color):
        self.color = color

    @abstractmethod
    def draw(self):
        pass

class Circle(Shape):
    def draw(self):
        return f"画圆圈,颜色:{self.color.fill()}"

# 使用
print(Circle(Red()).draw())  # 画圆圈,颜色:红色

应用场景

  • 设备驱动:抽象为设备,实现为平台(Windows/Linux)。
  • 优化你的设计:让NotificationBot持有“协议实现”类,避免深继承。

5. 其他相关模式简述

  • 抽象工厂(Abstract Factory):创建对象家族。扩展你的设计:工厂根据平台创建Bot实例。
  • 适配器(Adapter):兼容旧接口。e.g., 适配第三方API到你的send_message。

6. 最佳实践与注意事项

  • SOLID原则:你的设计符合“开闭原则”(扩展不修改)和“里氏替换”(子类可替基类)。
  • 何时选择:小项目用策略/模板;复杂用桥接避免继承问题。
  • 测试:用单元测试验证多态(e.g., mock子类)。
  • Python特色:用duck typing(不强制ABC)简化,但ABC提升类型安全。
  • 常见陷阱:过度设计——从简单继承开始,必要时重构。

7. 实践练习

  1. 扩展你的通知系统:添加微信Bot子类,实现send_message。
  2. 用策略模式重构排序示例,支持更多算法。
  3. 思考:如果通知需支持“加密+发送”,用桥接如何实现?

如果需要更详细代码、特定模式扩展,或基于你的代码修改,告诉我!

写文章用