文章目录
设计模式 之 建造者模式(C++)
建造者模式概述
建造者模式的核心在于将复杂对象的构建过程与其表示分离开来,使得同样的构建过程能够创建出不同的表示形式。简单来说,就是把对象的创建过程拆分成多个步骤,每个步骤由具体的建造者类负责完成,最后由指挥者类来协调这些步骤,从而完成对象的构建。
建造者模式的结构
建造者模式主要包含以下四个关键角色:
- 产品(Product):这是我们最终要构建的复杂对象,包含了对象的各种属性和行为。
- 抽象建造者(Builder):定义了创建产品各个部件的抽象方法,以及返回产品的方法,为具体建造者类提供了统一的接口。
- 具体建造者(Concrete Builder):实现了抽象建造者接口,具体负责实现创建产品各个部件的方法,根据不同的需求构建出不同的产品。
- 指挥者(Director):负责安排复杂对象的构建顺序,调用建造者的方法来完成产品的构建过程。
C++ 实现建造者模式示例
示例设计思路:
建造者模式通过将复杂对象的构建过程分解为独立步骤(由抽象建造者定义),由指挥者控制构建流程,具体建造者实现各步骤的组件装配,最终实现产品构建过程与组件实现的解耦,使得相同构建流程能创建不同配置的产品。
下面示例通过
Director
指挥MacBookBuilder
依次执行构建主板、显示器和操作系统(buildBoard(), buildDisplay(), buildOs())
的标准化流程,将计算机组件的具体实现(如Mac OS系统配置)封装在建造者内部,使同一构建流程能通过更换不同建造者(如未来添加的WindowsBuilder
)生成不同的计算机产品。
1. 产品类(Computer
)
#include<iostream>
#include <string>
#include <memory>
// 产品类:电脑,作为抽象基类
class Computer{
public:
// 构造函数
Computer(){}
// 设置主板信息
void setBoard(const std::string& board_name){
_board = board_name;
}
// 设置显示器信息
void setDisplay(const std::string &displayer_name) { _displayer = displayer_name; }
// 显示电脑配置信息
void showParamate(){
std::string param = "Computer: Paramater:\n";
param += "\tBoard: " + _board + "\n";
param += "\tDisplayer: " + _displayer + "\n";
param += "\tOS: " + _os + "\n";
std::cout << param << std::endl;
}
// 纯虚函数,用于设置操作系统,需由子类实现
virtual void setOs() = 0;
protected:
std::string _board; // 主板信息
std::string _displayer; // 显示器信息
std::string _os; // 操作系统信息
};
// 具体产品类:MacBook,继承自 Computer
class MacBook: public Computer{
public:
// 实现基类的纯虚函数,设置操作系统为 Mac OS
void setOs() override{
_os = "Mac OS";
}
};
Computer
类是我们要构建的电脑产品的抽象基类,包含了主板、显示器和操作系统三个重要属性。setBoard
和 setDisplay
方法用于设置主板和显示器的信息,showParamate
方法用于显示电脑的配置信息,setOs
是一个纯虚函数,需要由具体的子类实现。MacBook
类继承自 Computer
类,实现了 setOs
方法,将操作系统设置为 Mac OS
。
2. 抽象建造者类(Builder
)
// 抽象建造者类,定义构建电脑各部件的抽象方法
class Builder{
public:
// 抽象方法:构建主板
virtual void buildBoard(const std::string& board_name) = 0;
// 抽象方法:构建显示器
virtual void buildDisplay(const std::string& displayer_name) = 0;
// 抽象方法:构建操作系统
virtual void buildOs() = 0;
// 抽象方法:返回构建好的电脑对象
virtual std::shared_ptr<Computer> build() = 0;
};
Builder
是一个抽象类,定义了构建电脑各个部件的抽象方法 buildBoard
、buildDisplay
和 buildOs
,以及返回构建好的电脑对象的方法 build
。具体建造者类需要实现这些抽象方法。
3. 具体建造者类(MacBookBuilder
)
// 具体建造者类:负责构建 MacBook 电脑
class MacBookBuilder: public Builder{
public:
// 构造函数,创建一个新的 MacBook 对象
MacBookBuilder()
:_computer(new MacBook()){}
// 实现抽象方法:构建主板
void buildBoard(const std::string& board_name){
_computer->setBoard(board_name);
}
// 实现抽象方法:构建显示器
void buildDisplay(const std::string& displayer_name){
_computer->setDisplay(displayer_name);
}
// 实现抽象方法:构建操作系统
void buildOs(){
_computer->setOs();
}
// 实现抽象方法:返回构建好的电脑对象
std::shared_ptr<Computer> build(){
return _computer;
}
private:
std::shared_ptr<Computer> _computer; // 存储构建中的电脑对象
};
MacBookBuilder
是 Builder
的具体实现类,负责构建 MacBook
电脑。在构造函数中创建一个新的 MacBook
对象,然后在 buildBoard
、buildDisplay
和 buildOs
方法中分别为电脑设置具体的主板、显示器和操作系统信息。build
方法返回构建好的电脑对象。
4. 指挥者类(Director
)
// 指挥者类,负责安排电脑的构建顺序
class Director {
public:
// 构造函数,接收一个 Builder 指针
Director(Builder* builder):_builder(builder){}
// 按照顺序调用建造者的方法来构建电脑
void construct(const std::string& board_name, const std::string& displayer_name)
{
_builder->buildBoard(board_name);
_builder->buildDisplay(displayer_name);
_builder->buildOs();
}
private:
std::shared_ptr<Builder> _builder; // 存储建造者对象
};
Director
类负责安排电脑的构建顺序。在构造函数中接收一个 Builder
类型的指针,然后在 construct
方法中按照一定的顺序调用建造者的方法来构建电脑。
5. 客户端代码(main
函数)
int main(){
// 创建一个 MacBook 建造者对象
Builder* builder = new MacBookBuilder();
// 创建指挥者对象,并传入建造者指针
std::unique_ptr<Director> director(new Director(builder));
// 指挥者开始构建电脑,传入主板和显示器信息
director->construct("主板1", "显示器1");
// 通过建造者获取构建好的电脑对象
std::shared_ptr<Computer> computer = builder->build();
// 显示电脑的配置信息
computer->showParamate();
return 0;
}
在 main
函数中,首先创建一个 MacBookBuilder
对象,然后将其传递给 Director
对象。调用 Director
的 construct
方法开始构建电脑,传入主板和显示器的信息。最后通过建造者的 build
方法获取构建好的电脑对象,并调用其 showParamate
方法显示电脑配置信息。
建造者模式的优缺点
优点
- 分离构建与表示:将对象的构建过程和表示分离,使得构建过程更加清晰,易于维护和扩展。
- 创建不同表示的对象:可以方便地创建不同类型的产品,只需要更换具体的建造者类即可。
- 符合单一职责原则:每个建造者类只负责构建产品的一部分,职责明确,提高了代码的可维护性。
缺点
- 增加系统复杂度:需要创建多个类(产品类、抽象建造者类、具体建造者类和指挥者类),增加了系统的复杂度。
- 不适用于简单对象:对于简单对象的构建,使用建造者模式可能会显得过于繁琐。
建造者模式的适用场景
- 对象构建过程复杂:当一个对象的构建需要多个步骤,并且每个步骤都有不同的实现方式时,可以使用建造者模式。例如,创建一个汽车对象,需要依次安装发动机、轮胎、座椅等部件,每个部件的安装方式可能不同。
- 需要创建不同表示的对象:如果需要使用相同的构建过程来创建不同表示的对象,可以使用建造者模式。例如,创建不同配置的电脑,只需要更换具体的建造者类即可。
与其他模式的比较
与工厂模式的比较
工厂模式主要关注的是对象的创建,它隐藏了对象创建的细节,客户端只需要调用工厂方法即可获取对象。而建造者模式不仅关注对象的创建,还关注对象的构建过程,它将构建过程分解为多个步骤,通过指挥者来协调这些步骤的执行。
与抽象工厂模式的比较
抽象工厂模式主要用于创建一系列相关的对象,它返回的是一个产品族。而建造者模式主要用于创建一个复杂的对象,它通过多个步骤来构建这个对象。
工厂模式主要关注的是对象的创建,它隐藏了对象创建的细节,客户端只需要调用工厂方法即可获取对象。而建造者模式不仅关注对象的创建,还关注对象的构建过程,它将构建过程分解为多个步骤,通过指挥者来协调这些步骤的执行。
与抽象工厂模式的比较
抽象工厂模式主要用于创建一系列相关的对象,它返回的是一个产品族。而建造者模式主要用于创建一个复杂的对象,它通过多个步骤来构建这个对象。