动机(Motivation)
1、在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
2、如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?
基本概念
定义:构建器模式是一种创建型设计模式,它允许您分步骤创建复杂对象,使得相同的构建过程可以创建不同的表示。
构建器模式的核心思想是将复杂对象的构建与其表示分离,使得:
客户端不需要知道对象内部的具体组成细节
相同的构建过程可以创建不同的表示
可以更精细地控制对象的构建过程
实现方式
1. 经典构建器模式实现
#include <iostream>
#include <memory>
#include <string>
// 最终要构建的产品
class Pizza {
public:
void setDough(const std::string& dough) {
dough_ = dough;
}
void setSauce(const std::string& sauce) {
sauce_ = sauce;
}
void setTopping(const std::string& topping) {
topping_ = topping;
}
void showPizza() const {
std::cout << "Pizza with " << dough_ << " dough, "
<< sauce_ << " sauce and "
<< topping_ << " topping." << std::endl;
}
private:
std::string dough_;
std::string sauce_;
std::string topping_;
};
// 抽象构建器
class PizzaBuilder {
public:
virtual ~PizzaBuilder() = default;
Pizza* getPizza() {
return pizza_.get();
}
void createNewPizza() {
pizza_ = std::make_unique<Pizza>();
}
virtual void buildDough() = 0;
virtual void buildSauce() = 0;
virtual void buildTopping() = 0;
protected:
std::unique_ptr<Pizza> pizza_;
};
// 具体构建器 - HawaiianPizzaBuilder
class HawaiianPizzaBuilder : public PizzaBuilder {
public:
void buildDough() override {
pizza_->setDough("cross");
}
void buildSauce() override {
pizza_->setSauce("mild");
}
void buildTopping() override {
pizza_->setTopping("ham+pineapple");
}
};
// 具体构建器 - SpicyPizzaBuilder
class SpicyPizzaBuilder : public PizzaBuilder {
public:
void buildDough() override {
pizza_->setDough("pan baked");
}
void buildSauce() override {
pizza_->setSauce("hot");
}
void buildTopping() override {
pizza_->setTopping("pepperoni+salami");
}
};
// 指导者 (Director) - 控制构建过程
class Cook {
public:
void setPizzaBuilder(PizzaBuilder* pb) {
pizzaBuilder_ = pb;
}
Pizza* getPizza() {
return pizzaBuilder_->getPizza();
}
void constructPizza() {
pizzaBuilder_->createNewPizza();
pizzaBuilder_->buildDough();
pizzaBuilder_->buildSauce();
pizzaBuilder_->buildTopping();
}
private:
PizzaBuilder* pizzaBuilder_;
};
int main() {
Cook cook;
// 构建 Hawaiian Pizza
HawaiianPizzaBuilder hawaiianBuilder;
cook.setPizzaBuilder(&hawaiianBuilder);
cook.constructPizza();
Pizza* hawaiianPizza = cook.getPizza();
hawaiianPizza->showPizza(); // 输出: Pizza with cross dough, mild sauce and ham+pineapple topping.
// 构建 Spicy Pizza
SpicyPizzaBuilder spicyBuilder;
cook.setPizzaBuilder(&spicyBuilder);
cook.constructPizza();
Pizza* spicyPizza = cook.getPizza();
spicyPizza->showPizza(); // 输出: Pizza with pan baked dough, hot sauce and pepperoni+salami topping.
return 0;
}
2. 流式接口构建器 (更现代的C++实现)
#include <iostream>
#include <memory>
#include <string>
class Computer {
public:
void setCPU(const std::string& cpu) { cpu_ = cpu; }
void setRAM(const std::string& ram) { ram_ = ram; }
void setStorage(const std::string& storage) { storage_ = storage; }
void setGPU(const std::string& gpu) { gpu_ = gpu; }
void showSpecs() const {
std::cout << "Computer Specs:\n"
<< "CPU: " << cpu_ << "\n"
<< "RAM: " << ram_ << "\n"
<< "Storage: " << storage_ << "\n"
<< "GPU: " << (gpu_.empty() ? "Integrated" : gpu_) << "\n";
}
private:
std::string cpu_;
std::string ram_;
std::string storage_;
std::string gpu_;
};
class ComputerBuilder {
public:
ComputerBuilder() : computer_(std::make_unique<Computer>()) {}
ComputerBuilder& setCPU(const std::string& cpu) {
computer_->setCPU(cpu);
return *this;
}
ComputerBuilder& setRAM(const std::string& ram) {
computer_->setRAM(ram);
return *this;
}
ComputerBuilder& setStorage(const std::string& storage) {
computer_->setStorage(storage);
return *this;
}
ComputerBuilder& setGPU(const std::string& gpu) {
computer_->setGPU(gpu);
return *this;
}
std::unique_ptr<Computer> build() {
return std::move(computer_);
}
private:
std::unique_ptr<Computer> computer_;
};
int main() {
// 使用流式接口构建计算机
auto gamingPC = ComputerBuilder()
.setCPU("Intel i9-13900K")
.setRAM("32GB DDR5")
.setStorage("2TB NVMe SSD")
.setGPU("NVIDIA RTX 4090")
.build();
gamingPC->showSpecs();
auto officePC = ComputerBuilder()
.setCPU("AMD Ryzen 5")
.setRAM("16GB DDR4")
.setStorage("512GB SSD")
.build(); // 没有设置GPU
officePC->showSpecs();
return 0;
}
UML结构
构建器模式的优点
分步构建:可以分步骤构建复杂对象
复用构建过程:相同的构建过程可以创建不同的产品
单一职责原则:将复杂对象的构建代码与其业务逻辑分离
更好的控制:对构建过程有更精细的控制
可扩展性:添加新的具体构建器无需修改现有代码
适用场景
当创建复杂对象的算法应该独立于该对象的组成部分及其装配方式时
当构造过程必须允许被构造的对象有不同的表示时
当需要避免"伸缩构造函数"问题(构造函数参数过多)时
当对象有大量可选组件或配置时
构建器模式的变体
流式接口构建器:通过方法链提供更优雅的API
Groovy风格构建器:利用C++运算符重载实现更自然的语法
组合构建器:多个构建器协同工作构建复杂对象
注意事项
构建器模式会增加代码复杂度,因为需要创建多个新类
对于简单对象,直接使用构造函数可能更合适
确保构建器在构建完成后不能被重复使用(除非显式重置)
构建器模式在C++中特别适合用于创建配置复杂的对象,特别是当对象有许多可选组件时。流式接口的实现方式使得代码更加清晰易读。