Python设计模式 - 建造者模式

定义

建造者模式是一种创建型设计模式,主要用于构建包含多个组成部分的复杂对象。它将对象的构建过程与表示分离,使得同样的构建过程可以创建不同的对象表示。

结构

  • 抽象建造者(Builder):声明创建产品的各个部件的方法,以及一个获取产品对象的方法。
  • 具体建造者(ConcreteBuilder):实现抽象建造者的方法,这些方法用来构建产品的各个部件。
  • 产品(Product):被构建的复杂对象。
  • 指挥者(Director):负责安排产品各部件的建造顺序,调用抽象建造者的方法构建产品的各个部分,最后返回创建好的产品对象。
  • 客户端(Client):使用指挥者和建造者来构建产品。

应用场景

  1. 对象结构复杂,创建过程涉及多个步骤:当对象由多个组件组成,且这些组件的初始化顺序或组合方式较灵活时,建造者模式可以将创建过程拆分为多个步骤,使得对象的构建更加清晰。例如,构建 Computer 对象时,可以逐步配置 CPU、内存、硬盘等组件。
  2. 需要灵活配置对象:当对象的某些部分是可选的,或者可以根据不同需求定制时,建造者模式能够提供流畅的配置方式,而不影响对象的整体创建。例如,创建游戏角色时,可以选择不同的装备、技能组合,而无需修改底层实现。

优缺点

优点:

  1. 创建过程与表示分离:建造者模式将对象的创建过程和最终表示解耦,使得同样的构造过程可以创建不同的对象变体
  2. 封装复杂创建过程:将对象的创建流程封装在指挥者中,客户端无需关心具体的构造细节,而是通过指挥者直接获取完整的对象,从而简化调用逻辑。
  3. 提高代码的可扩展性:新增产品时,只需扩展新的具体建造者,而无需修改现有代码,符合开闭原则。

缺点:

  1. 可能导致冗余代码:对于每种不同的产品类型,都需要创建对应的建造者类,这在产品种类较多但构建逻辑相似的情况下,可能导致大量重复代码,不如使用抽象工厂模式更合适。

代码示例

python 复制代码
from abc import ABC, abstractmethod


class Computer:
    """ 计算机产品 """

    def __init__(self, brand):
        self.brand = brand
        self.cpu = None
        self.memory = None
        self.storage = None
        self.graphics_card = None  # 可选组件(独立显卡)

    def __str__(self):
        gpu_info = f", {self.graphics_card} GPU" if self.graphics_card else ", No GPU"
        return f"{self.brand} Computer with {self.cpu}, {self.memory} RAM, {self.storage} Storage{gpu_info}"


class ComputerBuilder(ABC):
    """ 计算机建造者基类(抽象类) """

    def __init__(self, brand):
        self.computer = Computer(brand)

    @abstractmethod
    def set_cpu(self):
        pass

    @abstractmethod
    def set_memory(self):
        pass

    @abstractmethod
    def set_storage(self):
        pass

    @abstractmethod
    def set_graphics_card(self):
        pass

    def build(self):
        return self.computer


class LenovoComputerBuilder(ComputerBuilder):
    """ 联想电脑建造者(默认带独立显卡) """

    def __init__(self):
        super().__init__("Lenovo")

    def set_cpu(self):
        self.computer.cpu = "Intel i7"
        return self

    def set_memory(self):
        self.computer.memory = "16GB"
        return self

    def set_storage(self):
        self.computer.storage = "512GB SSD"
        return self

    def set_graphics_card(self):
        self.computer.graphics_card = "NVIDIA RTX 4090"
        return self


class MacComputerBuilder(ComputerBuilder):
    """ Mac 电脑建造者(默认不带独立显卡) """

    def __init__(self):
        super().__init__("Mac")

    def set_cpu(self):
        self.computer.cpu = "Apple M2"
        return self

    def set_memory(self):
        self.computer.memory = "32GB"
        return self

    def set_storage(self):
        self.computer.storage = "1TB SSD"
        return self

    def set_graphics_card(self):
        return self


class Director:
    """ 指挥者,控制建造流程 """

    @staticmethod
    def construct_pc(builder: ComputerBuilder):
        """ 统一的构造过程 """
        return (builder.set_cpu()
                .set_memory()
                .set_storage()
                .set_graphics_card()
                .build())


# 客户端代码
lenovo_pc = Director.construct_pc(LenovoComputerBuilder())  # 联想默认带显卡
mac_pc = Director.construct_pc(MacComputerBuilder())  # Mac 默认无显卡

print(lenovo_pc)  # Lenovo Computer with Intel i7, 16GB RAM, 512GB SSD Storage, NVIDIA RTX 4090 GPU
print(mac_pc)  # Mac Computer with Apple M2, 32GB RAM, 1TB SSD Storage, No GPU

省略Director

在有些情况下,为了简化系统结构,可以将Director和抽象建造者Builder进行合并,在Builder中提供逐步构建复杂产品对象的construct()方法。

python 复制代码
class ComputerBuilder(ABC):
    """ 计算机建造者基类(抽象类) """

    def __init__(self, brand):
        self.computer = Computer(brand)

    @abstractmethod
    def set_cpu(self):
        pass

    @abstractmethod
    def set_memory(self):
        pass

    @abstractmethod
    def set_storage(self):
        pass

    @abstractmethod
    def set_graphics_card(self):
        pass

    def construct(self):
        """ 统一的构造过程 """
        return (self.set_cpu()
                .set_memory()
                .set_storage()
                .set_graphics_card()
                .computer)
                
# 客户端代码:直接选择 Builder 并调用 construct()
lenovo_pc = LenovoComputerBuilder().construct()  # 联想默认带显卡
mac_pc = MacComputerBuilder().construct()  # Mac 默认无显卡

print(lenovo_pc)  # Lenovo Computer with Intel i7, 16GB RAM, 512GB SSD Storage, NVIDIA RTX 4090 GPU
print(mac_pc)  # Mac Computer with Apple M2, 32GB RAM, 1TB SSD Storage, No GPU

这种方式不影响系统的灵活性和可扩展性,同时还简化了系统结构,但是加重了抽象建造者类的职责。如果construct()方法较为复杂,待构建产品的组成部分较多,建议还是将construct()方法单独封装在Director中,这样做更符合单一职责原则。

参考

《设计模式的艺术》

相关推荐
冷雨夜中漫步5 小时前
Python快速入门(6)——for/if/while语句
开发语言·经验分享·笔记·python
郝学胜-神的一滴5 小时前
深入解析Python字典的继承关系:从abc模块看设计之美
网络·数据结构·python·程序人生
百锦再5 小时前
Reactive编程入门:Project Reactor 深度指南
前端·javascript·python·react.js·django·前端框架·reactjs
喵手7 小时前
Python爬虫实战:旅游数据采集实战 - 携程&去哪儿酒店机票价格监控完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集结果csv导出·旅游数据采集·携程/去哪儿酒店机票价格监控
2501_944934737 小时前
高职大数据技术专业,CDA和Python认证优先考哪个?
大数据·开发语言·python
helloworldandy7 小时前
使用Pandas进行数据分析:从数据清洗到可视化
jvm·数据库·python
肖永威8 小时前
macOS环境安装/卸载python实践笔记
笔记·python·macos
TechWJ9 小时前
PyPTO编程范式深度解读:让NPU开发像写Python一样简单
开发语言·python·cann·pypto
枷锁—sha9 小时前
【SRC】SQL注入WAF 绕过应对策略(二)
网络·数据库·python·sql·安全·网络安全
abluckyboy9 小时前
Java 实现求 n 的 n^n 次方的最后一位数字
java·python·算法