概念
建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。该模式允许你逐步构建复杂对象,同时将构建步骤的具体实现封装起来,客户端只需要指定要构建的对象类型,而不需要关心对象的具体构建细节。
优缺点
优点
- 封装性和可维护性高:将对象构建过程封装,降低模块耦合,客户端无需了解细节,便于代码维护。
- 可扩展性强:构建与表示分离,新增对象表示时只需创建新的具体建造者类,无需修改其他代码。
- 控制构建过程:指挥者可控制构建顺序,确保有严格顺序要求的对象能按特定步骤构建。
- 提高代码复用性:具体建造者的构建方法可复用,避免相同构建步骤的重复编写。
缺点
-
代码复杂度增加:引入多个角色和类,使代码复杂、类数量增多,简单对象创建用此模式会繁琐。
若建造过程简单,可考虑将指挥者和抽象建造者的功能合并。比如小型软件项目中,对象构建步骤少且固定,就无需单独的指挥者类,让具体建造者直接负责控制构建顺序,减少类的数量和交互复杂度。
-
适用范围有限:主要适用于复杂对象,对简单对象或无明显构建步骤和顺序要求的对象不适用。
-
增加系统开销:创建多个类和对象会增加内存占用和创建时间,影响对性能要求高的系统。
示例
为方便理解,下面我们以建造电脑为例,使用建造者模式来实现。电脑是我们要创建的复杂对象,包括 CPU、内存、硬盘等组件。
C++实现
为避免手动管理内存,减少内存泄露风险,C++实现使用智能指针管理对象
#include <iostream>
#include <string>
#include <memory>
// 产品:电脑
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<Computer> getComputer() = 0;
};
// 具体建造者:高端电脑建造者
class HighEndComputerBuilder : public ComputerBuilder {
public:
HighEndComputerBuilder() {
m_computer = std::make_unique<Computer>();
}
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<Computer> getComputer() override {
return std::move(m_computer);
}
private:
std::unique_ptr<Computer> m_computer;
};
// 具体建造者:低端电脑建造者
class LowEndComputerBuilder : public ComputerBuilder {
public:
LowEndComputerBuilder() {
m_computer = std::make_unique<Computer>();
}
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<Computer> getComputer() override {
return std::move(m_computer);
}
private:
std::unique_ptr<Computer> m_computer;
};
// 指挥者
class ComputerDirector {
public:
explicit ComputerDirector(std::unique_ptr<ComputerBuilder> builder)
: m_builder(std::move(builder)) {}
std::unique_ptr<Computer> constructComputer() {
m_builder->buildCPU();
m_builder->buildMemory();
m_builder->buildHardDisk();
return m_builder->getComputer();
}
private:
std::unique_ptr<ComputerBuilder> m_builder;
};
int main() {
// 建造高端电脑
auto highEndBuilder = std::make_unique<HighEndComputerBuilder>();
ComputerDirector highEndDirector(std::move(highEndBuilder));
auto highEndComputer = highEndDirector.constructComputer();
std::cout << "High End Computer Info:" << std::endl;
highEndComputer->showInfo();
// 建造低端电脑
auto lowEndBuilder = std::make_unique<LowEndComputerBuilder>();
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();
}
}
代码解释
- Computer 类:表示要创建的产品,即电脑,包含了设置 CPU、内存、硬盘等组件的方法,以及显示电脑信息的方法。
- ComputerBuilder 类:抽象建造者,定义了创建电脑各个部分的抽象方法,以及返回最终电脑对象的方法。
- HighEndComputerBuilder 类和 LowEndComputerBuilder 类:具体建造者,分别实现了抽象建造者接口,负责构建高端电脑和低端电脑。
- ComputerDirector 类:指挥者,负责安排电脑的构建顺序,调用具体建造者的方法来构建电脑。
- main 函数:客户端代码,创建具体建造者和指挥者对象,调用指挥者的方法来构建电脑,并显示电脑信息。
核心角色及其作用
基于上述代码,对建造者模式的相关“角色”加以解释说明。
- 产品(Product)
- 含义:产品是建造者模式最终要创建的复杂对象。它由多个部分组成,每个部分可能具有不同的属性和特点。
- 作用:是整个建造过程的目标,所有的构建操作都是为了生成一个完整的产品实例。在上述例子中,
Computer
类就是产品,它包含了 CPU、内存、硬盘等多个组件。
- 抽象建造者(Builder)
- 含义:抽象建造者是一个抽象类或接口,定义了创建产品各个部分的抽象方法,以及返回最终产品的方法。
- 作用:为具体建造者提供了统一的构建规范,规定了构建产品的基本步骤。通过这种方式,保证了不同的具体建造者都遵循相同的构建流程。例如
ComputerBuilder
类,它定义了buildCPU
、buildMemory
、buildHardDisk
等方法,用于构建电脑的各个组件。
- 具体建造者(Concrete Builder)
- 含义:具体建造者实现了抽象建造者接口,负责具体的构建过程。每个具体建造者根据需求实现抽象建造者中定义的方法,以构建出不同类型或配置的产品。
- 作用:将抽象的构建步骤具体化,根据具体的业务需求来创建产品的各个部分。例如
HighEndComputerBuilder
和LowEndComputerBuilder
类,分别实现了构建高端电脑和低端电脑的具体逻辑。
- 指挥者(Director)
- 含义:指挥者负责安排复杂对象的构建顺序,调用具体建造者的方法来构建产品。它不负责产品的具体构建细节,只关注构建的流程和顺序。
- 作用:对构建过程进行统一管理,使得构建过程更加有序和可控。客户端只需要与指挥者进行交互,而不需要关心具体的构建步骤。例如
ComputerDirector
类,它调用具体建造者的buildCPU
、buildMemory
、buildHardDisk
方法,按照一定的顺序构建电脑。
UML图
工作流程
- 客户端创建具体建造者对象:客户端根据需要选择合适的具体建造者,例如要创建高端电脑就选择
HighEndComputerBuilder
,要创建低端电脑就选择LowEndComputerBuilder
。 - 客户端创建指挥者对象并传入具体建造者:将创建好的具体建造者对象传递给指挥者,指挥者将使用这个具体建造者来完成产品的构建。例如
ComputerDirector highEndDirector(&highEndBuilder);
。 - 指挥者调用具体建造者的方法进行构建:指挥者按照预定的顺序调用具体建造者的方法,逐步构建产品的各个部分。例如
highEndDirector.constructComputer();
方法会依次调用highEndBuilder
的buildCPU
、buildMemory
、buildHardDisk
方法。 - 客户端从具体建造者或指挥者获取最终产品:构建完成后,客户端可以从具体建造者或指挥者处获取最终的产品实例。例如
Computer highEndComputer = highEndDirector.getComputer();
。
与工厂模式的对比
比较维度 | 工厂模式 | 建造者模式 |
相同点 | 都属于创建型设计模式,主要目的都是封装对象的创建过程,将对象的创建和使用分离,提高代码的可维护性和可扩展性,让客户端无需关注对象创建的具体细节,只需调用相应的接口获取对象即可。 | |
不同点 | ||
目的侧重点 | 重点在于提供一种统一的方式来创建不同类型的对象,更强调对象创建的结果,关注如何根据不同的条件创建出不同类型的对象实例。 | 强调对象的构建过程,注重将一个复杂对象的构建过程和表示分离,允许按步骤构建对象,能灵活控制对象的构建细节。 |
复杂度与构建步骤 | 创建过程相对简单,通常是根据传入的参数或条件一次性创建出完整的对象,不涉及多个复杂的构建步骤。 | 适用于创建复杂对象,对象的构建过程由多个步骤组成,每个步骤可能有不同的操作和配置,通过逐步调用不同的构建方法来完成对象的创建。 |
代码结构与角色 | 一般包含工厂类和产品类。工厂类负责对象的创建逻辑,产品类是工厂创建的目标对象。 | 包含产品、抽象建造者、具体建造者和指挥者四个主要角色。抽象建造者定义构建步骤,具体建造者实现构建逻辑,指挥者控制构建顺序。 |
灵活性 | 创建逻辑相对固定,一旦确定创建规则,较难在创建过程中动态调整对象的属性和配置。 | 灵活性高,可以根据不同需求灵活调整对象的构建过程,通过不同的具体建造者和指挥者组合创建不同表示和配置的对象。 |
应用方向 | ||
应用场景 | - 创建对象的逻辑相对简单,只需要根据不同条件返回不同类型的对象时使用,如创建不同类型的数据库连接对象。 - 需要创建多种相关但又有区别的对象时,例如不同风格的按钮、不同格式的文档解析器等。 | - 创建复杂对象,且对象的构建过程有明显的步骤划分,如构建电脑、汽车等产品。 - 需要根据不同的配置或参数组合来创建对象时,如创建不同套餐的旅游行程、不同规格的房屋等。 |
示例 | 文件读取器工厂可以根据文件类型(如文本文件、CSV 文件、JSON 文件)创建不同的读取器对象。 | 游戏角色创建系统,可逐步设置角色的外貌、技能、装备等属性来创建不同类型的角色。 |
应用场景
建造者模式将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。上述与工厂模式的对比中已经简要陈述了应用场景,此处做更详细地说明。
构建复杂对象
当需要创建的对象是由多个部分组成,且各个部分的构建过程较为复杂,同时构建顺序也可能不同时,建造者模式非常适用。它可以将复杂对象的构建过程分解为多个简单的步骤,每个步骤由具体建造者负责实现,从而提高代码的可维护性和可扩展性。
- 汽车制造
- 场景描述:汽车是一个复杂的产品,由发动机、底盘、车身、电气设备等多个部分组成。不同类型的汽车(如轿车、SUV、卡车)在各个部分的配置和规格上可能存在差异。
- 使用方式:可以定义一个抽象建造者接口,包含构建发动机、底盘、车身等部分的抽象方法,以及返回最终汽车对象的方法。然后为每种类型的汽车创建具体的建造者类,实现抽象建造者接口中的方法。最后,通过指挥者类来控制汽车的构建顺序,确保各个部分按照正确的顺序进行组装。
- 电脑组装
- 场景描述:电脑由 CPU、内存、硬盘、显卡、主板等多个组件组成。不同用途的电脑(如办公电脑、游戏电脑、图形工作站)在组件的选择和配置上有很大区别。
- 使用方式:设计一个抽象建造者类,定义构建各个组件的方法。针对不同类型的电脑,创建具体的建造者类,实现相应的构建方法。指挥者类根据用户需求,调用具体建造者的方法,逐步构建出符合要求的电脑。
对象配置组合多样
如果一个对象有多种不同的配置组合方式,并且这些配置组合的创建过程较为复杂,使用建造者模式可以方便地管理和创建这些不同的配置。
- 旅游套餐定制
- 场景描述:旅游套餐通常包含交通方式(飞机、火车、汽车)、住宿类型(酒店、民宿、度假村)、景点游览等多个元素。不同的游客可能有不同的需求,形成各种不同的旅游套餐组合。
- 使用方式:创建一个抽象建造者类,其中包含设置交通方式、住宿类型、景点安排等方法。为不同类型的旅游套餐(如豪华游、经济游、亲子游)创建具体的建造者类,实现抽象建造者的方法。指挥者类根据游客的需求,调用具体建造者的方法,生成定制化的旅游套餐。
- 手机套餐定制
- 场景描述:手机套餐包含通话时长、短信数量、流量额度、增值服务等多个方面。运营商为了满足不同用户的需求,提供了多种套餐组合。
- 使用方式:定义一个抽象建造者接口,包含设置通话时长、短信数量、流量额度等方法。针对不同的套餐类型(如学生套餐、商务套餐、老年套餐),创建具体的建造者类,实现接口中的方法。指挥者类根据用户选择,调用具体建造者的方法,生成合适的手机套餐。
需要控制构建顺序
当对象的构建过程有严格的顺序要求时,建造者模式可以通过指挥者类来控制构建步骤的执行顺序,确保对象按照正确的顺序进行构建。
- 房屋建造
- 场景描述:房屋建造有严格的施工顺序,通常先进行基础工程(打地基),然后是主体结构建设(砌墙、搭建框架),接着进行装修工程(墙面处理、安装门窗)等。
- 使用方式:设计一个抽象建造者类,包含基础工程、主体结构建设、装修工程等抽象方法。为不同类型的房屋(如别墅、公寓、办公楼)创建具体的建造者类,实现抽象方法。指挥者类按照房屋建造的顺序,依次调用具体建造者的方法,完成房屋的建造。
- 软件开发项目
- 场景描述:软件开发项目的开发过程通常包括需求分析、设计、编码、测试、部署等阶段,每个阶段都有特定的任务和输出,且顺序一般是固定的。
- 使用方式:创建一个抽象建造者类,定义需求分析、设计、编码、测试、部署等方法。针对不同类型的软件项目(如 Web 应用、移动应用、桌面应用),创建具体的建造者类,实现抽象方法。指挥者类按照软件开发的流程,调用具体建造者的方法,完成软件项目的开发。