设计模式之建造者模式

概念

建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。该模式允许你逐步构建复杂对象,同时将构建步骤的具体实现封装起来,客户端只需要指定要构建的对象类型,而不需要关心对象的具体构建细节。

优缺点

优点

  • 封装性和可维护性高:将对象构建过程封装,降低模块耦合,客户端无需了解细节,便于代码维护。
  • 可扩展性强:构建与表示分离,新增对象表示时只需创建新的具体建造者类,无需修改其他代码。
  • 控制构建过程:指挥者可控制构建顺序,确保有严格顺序要求的对象能按特定步骤构建。
  • 提高代码复用性:具体建造者的构建方法可复用,避免相同构建步骤的重复编写。

缺点

  • 代码复杂度增加:引入多个角色和类,使代码复杂、类数量增多,简单对象创建用此模式会繁琐。

    若建造过程简单,可考虑将指挥者和抽象建造者的功能合并。比如小型软件项目中,对象构建步骤少且固定,就无需单独的指挥者类,让具体建造者直接负责控制构建顺序,减少类的数量和交互复杂度。

  • 适用范围有限:主要适用于复杂对象,对简单对象或无明显构建步骤和顺序要求的对象不适用。

  • 增加系统开销:创建多个类和对象会增加内存占用和创建时间,影响对性能要求高的系统。

示例

为方便理解,下面我们以建造电脑为例,使用建造者模式来实现。电脑是我们要创建的复杂对象,包括 CPU、内存、硬盘等组件。

C++实现

为避免手动管理内存,减少内存泄露风险,C++实现使用智能指针管理对象

#include 
#include 
#include 

// 产品:电脑
class Computer {
public:
    void setCPU(const std::string& cpu) {
        m_cpu = cpu;
    }

    void setMemory(const std::string& memory) {
        m_memory = memory;
    }

    void setHardDisk(const std::string& hardDisk) {
        m_hardDisk = hardDisk;
    }

    void showInfo() const {
        std::cout << "CPU: " << m_cpu << std::endl;
        std::cout << "Memory: " << m_memory << std::endl;
        std::cout << "Hard Disk: " << m_hardDisk << std::endl;
    }

private:
    std::string m_cpu;
    std::string m_memory;
    std::string m_hardDisk;
};

// 抽象建造者
class ComputerBuilder {
public:
    virtual ~ComputerBuilder() = default;
    virtual void buildCPU() = 0;
    virtual void buildMemory() = 0;
    virtual void buildHardDisk() = 0;
    virtual std::unique_ptr getComputer() = 0;
};

// 具体建造者:高端电脑建造者
class HighEndComputerBuilder : public ComputerBuilder {
public:
    HighEndComputerBuilder() {
        m_computer = std::make_unique();
    }

    void buildCPU() override {
        m_computer->setCPU("Intel Core i9");
    }

    void buildMemory() override {
        m_computer->setMemory("64GB DDR5");
    }

    void buildHardDisk() override {
        m_computer->setHardDisk("2TB SSD");
    }

    std::unique_ptr getComputer() override {
        return std::move(m_computer);
    }

private:
    std::unique_ptr m_computer;
};

// 具体建造者:低端电脑建造者
class LowEndComputerBuilder : public ComputerBuilder {
public:
    LowEndComputerBuilder() {
        m_computer = std::make_unique();
    }

    void buildCPU() override {
        m_computer->setCPU("Intel Core i3");
    }

    void buildMemory() override {
        m_computer->setMemory("8GB DDR4");
    }

    void buildHardDisk() override {
        m_computer->setHardDisk("500GB HDD");
    }

    std::unique_ptr getComputer() override {
        return std::move(m_computer);
    }

private:
    std::unique_ptr m_computer;
};

// 指挥者
class ComputerDirector {
public:
    explicit ComputerDirector(std::unique_ptr builder) 
        : m_builder(std::move(builder)) {}

    std::unique_ptr constructComputer() {
        m_builder->buildCPU();
        m_builder->buildMemory();
        m_builder->buildHardDisk();
        return m_builder->getComputer();
    }

private:
    std::unique_ptr m_builder;
};

int main() {
    // 建造高端电脑
    auto highEndBuilder = std::make_unique();
    ComputerDirector highEndDirector(std::move(highEndBuilder));
    auto highEndComputer = highEndDirector.constructComputer();
    std::cout << "High End Computer Info:" << std::endl;
    highEndComputer->showInfo();

    // 建造低端电脑
    auto lowEndBuilder = std::make_unique();
    ComputerDirector lowEndDirector(std::move(lowEndBuilder));
    auto lowEndComputer = lowEndDirector.constructComputer();
    std::cout << "\nLow End Computer Info:" << std::endl;
    lowEndComputer->showInfo();

    return 0;
}

Java实现

// 产品:电脑
class Computer {
    private String cpu;
    private String memory;
    private String hardDisk;

    public void setCPU(String cpu) {
        this.cpu = cpu;
    }

    public void setMemory(String memory) {
        this.memory = memory;
    }

    public void setHardDisk(String hardDisk) {
        this.hardDisk = hardDisk;
    }

    public void showInfo() {
        System.out.println("CPU: " + cpu);
        System.out.println("Memory: " + memory);
        System.out.println("Hard Disk: " + hardDisk);
    }
}

// 抽象建造者
interface ComputerBuilder {
    void buildCPU();
    void buildMemory();
    void buildHardDisk();
    Computer getComputer();
}

// 具体建造者:高端电脑建造者
class HighEndComputerBuilder implements ComputerBuilder {
    private Computer computer;

    public HighEndComputerBuilder() {
        this.computer = new Computer();
    }

    @Override
    public void buildCPU() {
        computer.setCPU("Intel Core i9");
    }

    @Override
    public void buildMemory() {
        computer.setMemory("64GB DDR5");
    }

    @Override
    public void buildHardDisk() {
        computer.setHardDisk("2TB SSD");
    }

    @Override
    public Computer getComputer() {
        return this.computer;
    }
}

// 具体建造者:低端电脑建造者
class LowEndComputerBuilder implements ComputerBuilder {
    private Computer computer;

    public LowEndComputerBuilder() {
        this.computer = new Computer();
    }

    @Override
    public void buildCPU() {
        computer.setCPU("Intel Core i3");
    }

    @Override
    public void buildMemory() {
        computer.setMemory("8GB DDR4");
    }

    @Override
    public void buildHardDisk() {
        computer.setHardDisk("500GB HDD");
    }

    @Override
    public Computer getComputer() {
        return this.computer;
    }
}

// 指挥者
class ComputerDirector {
    private ComputerBuilder builder;

    public ComputerDirector(ComputerBuilder builder) {
        this.builder = builder;
    }

    public Computer constructComputer() {
        builder.buildCPU();
        builder.buildMemory();
        builder.buildHardDisk();
        return builder.getComputer();
    }
}

// 主类
public class BuilderPatternDemo {
    public static void main(String[] args) {
        // 建造高端电脑
        ComputerBuilder highEndBuilder = new HighEndComputerBuilder();
        ComputerDirector highEndDirector = new ComputerDirector(highEndBuilder);
        Computer highEndComputer = highEndDirector.constructComputer();
        System.out.println("High End Computer Info:");
        highEndComputer.showInfo();

        // 建造低端电脑
        ComputerBuilder lowEndBuilder = new LowEndComputerBuilder();
        ComputerDirector lowEndDirector = new ComputerDirector(lowEndBuilder);
        Computer lowEndComputer = lowEndDirector.constructComputer();
        System.out.println("\nLow End Computer Info:");
        lowEndComputer.showInfo();
    }
}

代码解释

  1. Computer 类:表示要创建的产品,即电脑,包含了设置 CPU、内存、硬盘等组件的方法,以及显示电脑信息的方法。
  2. ComputerBuilder 类:抽象建造者,定义了创建电脑各个部分的抽象方法,以及返回最终电脑对象的方法。
  3. HighEndComputerBuilder 类和 LowEndComputerBuilder 类:具体建造者,分别实现了抽象建造者接口,负责构建高端电脑和低端电脑。
  4. ComputerDirector 类:指挥者,负责安排电脑的构建顺序,调用具体建造者的方法来构建电脑。
  5. main 函数:客户端代码,创建具体建造者和指挥者对象,调用指挥者的方法来构建电脑,并显示电脑信息。

核心角色及其作用

基于上述代码,对建造者模式的相关“角色”加以解释说明。

  1. 产品(Product)
    • 含义:产品是建造者模式最终要创建的复杂对象。它由多个部分组成,每个部分可能具有不同的属性和特点。
    • 作用:是整个建造过程的目标,所有的构建操作都是为了生成一个完整的产品实例。在上述例子中,Computer类就是产品,它包含了 CPU、内存、硬盘等多个组件。
  2. 抽象建造者(Builder)
    • 含义:抽象建造者是一个抽象类或接口,定义了创建产品各个部分的抽象方法,以及返回最终产品的方法。
    • 作用:为具体建造者提供了统一的构建规范,规定了构建产品的基本步骤。通过这种方式,保证了不同的具体建造者都遵循相同的构建流程。例如ComputerBuilder类,它定义了buildCPUbuildMemorybuildHardDisk等方法,用于构建电脑的各个组件。
  3. 具体建造者(Concrete Builder)
    • 含义:具体建造者实现了抽象建造者接口,负责具体的构建过程。每个具体建造者根据需求实现抽象建造者中定义的方法,以构建出不同类型或配置的产品。
    • 作用:将抽象的构建步骤具体化,根据具体的业务需求来创建产品的各个部分。例如HighEndComputerBuilderLowEndComputerBuilder类,分别实现了构建高端电脑和低端电脑的具体逻辑。
  4. 指挥者(Director)
    • 含义:指挥者负责安排复杂对象的构建顺序,调用具体建造者的方法来构建产品。它不负责产品的具体构建细节,只关注构建的流程和顺序。
    • 作用:对构建过程进行统一管理,使得构建过程更加有序和可控。客户端只需要与指挥者进行交互,而不需要关心具体的构建步骤。例如ComputerDirector类,它调用具体建造者的buildCPUbuildMemorybuildHardDisk方法,按照一定的顺序构建电脑。

UML图

设计模式之建造者模式_第1张图片

工作流程

  1. 客户端创建具体建造者对象:客户端根据需要选择合适的具体建造者,例如要创建高端电脑就选择HighEndComputerBuilder,要创建低端电脑就选择LowEndComputerBuilder
  2. 客户端创建指挥者对象并传入具体建造者:将创建好的具体建造者对象传递给指挥者,指挥者将使用这个具体建造者来完成产品的构建。例如ComputerDirector highEndDirector(&highEndBuilder);
  3. 指挥者调用具体建造者的方法进行构建:指挥者按照预定的顺序调用具体建造者的方法,逐步构建产品的各个部分。例如highEndDirector.constructComputer();方法会依次调用highEndBuilderbuildCPUbuildMemorybuildHardDisk方法。
  4. 客户端从具体建造者或指挥者获取最终产品:构建完成后,客户端可以从具体建造者或指挥者处获取最终的产品实例。例如Computer highEndComputer = highEndDirector.getComputer();

与工厂模式的对比

比较维度 工厂模式 建造者模式
相同点 都属于创建型设计模式,主要目的都是封装对象的创建过程,将对象的创建和使用分离,提高代码的可维护性和可扩展性,让客户端无需关注对象创建的具体细节,只需调用相应的接口获取对象即可。
不同点
目的侧重点 重点在于提供一种统一的方式来创建不同类型的对象,更强调对象创建的结果,关注如何根据不同的条件创建出不同类型的对象实例。 强调对象的构建过程,注重将一个复杂对象的构建过程和表示分离,允许按步骤构建对象,能灵活控制对象的构建细节。
复杂度与构建步骤 创建过程相对简单,通常是根据传入的参数或条件一次性创建出完整的对象,不涉及多个复杂的构建步骤。 适用于创建复杂对象,对象的构建过程由多个步骤组成,每个步骤可能有不同的操作和配置,通过逐步调用不同的构建方法来完成对象的创建。
代码结构与角色 一般包含工厂类和产品类。工厂类负责对象的创建逻辑,产品类是工厂创建的目标对象。 包含产品、抽象建造者、具体建造者和指挥者四个主要角色。抽象建造者定义构建步骤,具体建造者实现构建逻辑,指挥者控制构建顺序。
灵活性 创建逻辑相对固定,一旦确定创建规则,较难在创建过程中动态调整对象的属性和配置。 灵活性高,可以根据不同需求灵活调整对象的构建过程,通过不同的具体建造者和指挥者组合创建不同表示和配置的对象。
应用方向
应用场景 - 创建对象的逻辑相对简单,只需要根据不同条件返回不同类型的对象时使用,如创建不同类型的数据库连接对象。 - 需要创建多种相关但又有区别的对象时,例如不同风格的按钮、不同格式的文档解析器等。 - 创建复杂对象,且对象的构建过程有明显的步骤划分,如构建电脑、汽车等产品。 - 需要根据不同的配置或参数组合来创建对象时,如创建不同套餐的旅游行程、不同规格的房屋等。
示例 文件读取器工厂可以根据文件类型(如文本文件、CSV 文件、JSON 文件)创建不同的读取器对象。 游戏角色创建系统,可逐步设置角色的外貌、技能、装备等属性来创建不同类型的角色。

应用场景

建造者模式将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。上述与工厂模式的对比中已经简要陈述了应用场景,此处做更详细地说明。

构建复杂对象

当需要创建的对象是由多个部分组成,且各个部分的构建过程较为复杂,同时构建顺序也可能不同时,建造者模式非常适用。它可以将复杂对象的构建过程分解为多个简单的步骤,每个步骤由具体建造者负责实现,从而提高代码的可维护性和可扩展性。

  • 汽车制造
    • 场景描述:汽车是一个复杂的产品,由发动机、底盘、车身、电气设备等多个部分组成。不同类型的汽车(如轿车、SUV、卡车)在各个部分的配置和规格上可能存在差异。
    • 使用方式:可以定义一个抽象建造者接口,包含构建发动机、底盘、车身等部分的抽象方法,以及返回最终汽车对象的方法。然后为每种类型的汽车创建具体的建造者类,实现抽象建造者接口中的方法。最后,通过指挥者类来控制汽车的构建顺序,确保各个部分按照正确的顺序进行组装。
  • 电脑组装
    • 场景描述:电脑由 CPU、内存、硬盘、显卡、主板等多个组件组成。不同用途的电脑(如办公电脑、游戏电脑、图形工作站)在组件的选择和配置上有很大区别。
    • 使用方式:设计一个抽象建造者类,定义构建各个组件的方法。针对不同类型的电脑,创建具体的建造者类,实现相应的构建方法。指挥者类根据用户需求,调用具体建造者的方法,逐步构建出符合要求的电脑。

对象配置组合多样

如果一个对象有多种不同的配置组合方式,并且这些配置组合的创建过程较为复杂,使用建造者模式可以方便地管理和创建这些不同的配置。

  • 旅游套餐定制
    • 场景描述:旅游套餐通常包含交通方式(飞机、火车、汽车)、住宿类型(酒店、民宿、度假村)、景点游览等多个元素。不同的游客可能有不同的需求,形成各种不同的旅游套餐组合。
    • 使用方式:创建一个抽象建造者类,其中包含设置交通方式、住宿类型、景点安排等方法。为不同类型的旅游套餐(如豪华游、经济游、亲子游)创建具体的建造者类,实现抽象建造者的方法。指挥者类根据游客的需求,调用具体建造者的方法,生成定制化的旅游套餐。
  • 手机套餐定制
    • 场景描述:手机套餐包含通话时长、短信数量、流量额度、增值服务等多个方面。运营商为了满足不同用户的需求,提供了多种套餐组合。
    • 使用方式:定义一个抽象建造者接口,包含设置通话时长、短信数量、流量额度等方法。针对不同的套餐类型(如学生套餐、商务套餐、老年套餐),创建具体的建造者类,实现接口中的方法。指挥者类根据用户选择,调用具体建造者的方法,生成合适的手机套餐。

需要控制构建顺序

当对象的构建过程有严格的顺序要求时,建造者模式可以通过指挥者类来控制构建步骤的执行顺序,确保对象按照正确的顺序进行构建。

  • 房屋建造
    • 场景描述:房屋建造有严格的施工顺序,通常先进行基础工程(打地基),然后是主体结构建设(砌墙、搭建框架),接着进行装修工程(墙面处理、安装门窗)等。
    • 使用方式:设计一个抽象建造者类,包含基础工程、主体结构建设、装修工程等抽象方法。为不同类型的房屋(如别墅、公寓、办公楼)创建具体的建造者类,实现抽象方法。指挥者类按照房屋建造的顺序,依次调用具体建造者的方法,完成房屋的建造。
  • 软件开发项目
    • 场景描述:软件开发项目的开发过程通常包括需求分析、设计、编码、测试、部署等阶段,每个阶段都有特定的任务和输出,且顺序一般是固定的。
    • 使用方式:创建一个抽象建造者类,定义需求分析、设计、编码、测试、部署等方法。针对不同类型的软件项目(如 Web 应用、移动应用、桌面应用),创建具体的建造者类,实现抽象方法。指挥者类按照软件开发的流程,调用具体建造者的方法,完成软件项目的开发。

你可能感兴趣的:(设计模式,设计模式,建造者模式,c++,java)