广告

C++实现建造者设计模式:分离复杂对象的构造与表示的实战教程

1.1 建造者设计模式的核心思想与目标

核心目标是将复杂对象的构造过程与对象的最终表示分离,从而在不改变客户端代码的情况下,灵活地切换不同的部件组合和表示方式。通过这种分离,重复的构造步骤可以复用,而对象表示的变化也能独立演化。

在实际的软件架构中,这意味着你可以将一个复杂对象的组装分解成若干阶段,并通过不同的实现来提供不同的部件组合。分离构造与表示不仅降低了耦合,而且有助于实现可维护性与可扩展性,尤其当产品有多种不同版本时。

1.2 在实践中如何体现分离与可扩展性

通过引入 Product、Builder、ConcreteBuilder、Director 等角色,建造者模式实现了构造流程与表示的解耦。Director 负责按固定工艺顺序组装,而 ConcreteBuilder 负责具体部件的实现,这使得新增一个新版本的表示时无需修改客户端代码。

在面向对象设计中,你可以复用同一套构造步骤来生成不同的产品版本,从而实现对硬件、软件或配置对象的统一建造过程。对于需要可配置的构造流程的场景,建造者模式往往能带来显著的灵活性与可维护性提升。

2.1 Product:最终复杂对象的表示与部件

Product表示被构造的最终对象,通常包含多个部件或属性。它将作为客户端所看到的“成品”呈现,与具体的构造流程解耦。通过将部件组合的细节封装到 Product 实例中,客户端无需关心构造细节即可使用成品。

在 C++ 的实现中,Product 常以一个结构或类来承载多组部件信息,并提供简单的访问接口供客户端展示或落地输出。正确地封装这些成员变量,可以提高代码的可读性与可测试性。

2.2 Builder:抽象接口定义构造步骤

Builder作为抽象接口,声明了构造复杂对象各个部件的步骤。它并不关心部件的具体实现,只描述能被组合的构造动作。通过纯虚方法实现跨实现的多态性。

借助 Builder,不同的 ConcreteBuilder 可以实现相同的构造步骤,从而产生不同的 Product 表示。Director 将调用顺序固化,确保构造流程的一致性。

2.3 ConcreteBuilder:具体实现,维护产品实例

ConcreteBuilder负责实现 Builder 接口中的构造步骤,并维护一个 Product 实例,逐步填充部件信息。它的职责是把构造细节具体化为某种表示的部件。

在构造完成后,ConcreteBuilder 提供 getResult() 方法返回最终的 Product。通过不同的 ConcreteBuilder(如豪华版、经济版等),可以在不修改客户端代码的前提下扩展产品的表示。

2.4 Director:控制构造过程的流程

Director负责按照固定的工艺流程调用 Builder 的构造方法,从而实现一个稳定的生产线。它对外暴露的通常是一个组装入口,确保产品在不同需求版本下有一致的构造顺序

通过组合不同的 Builder,Director 可以生成多种不同的 Product 表示,而无需让客户端直接管理部件的创建顺序。这是实现灵活配置与版本控制的重要机制。

C++实现建造者设计模式:分离复杂对象的构造与表示的实战教程

3. 实战示例:C++ 实现分离构造与表示的汽车对象

3.1 需求分析与设计要点

在本实战中,我们要通过建造者模式,把发动机、轮胎、车身等部件的构造与最终汽车的表示分离,以便同一套构造步骤可以生成不同规格的车型(如经济版、豪华版)。C++ 实现需要清晰地分离接口与实现,并通过 Director 控制组装流程。

设计要点包括:Product 的部件信息封装Builder 的抽象接口ConcreteBuilder 的具体实现、以及 Director 的组装流程,三者协同实现分离的构造与表示。

3.2 代码实现:结构与关键点

下面给出一个简化的车对象构造示例,包括 Product、Builder、ConcreteBuilder、Director 以及客户端示例。你可以通过扩展 ConcreteBuilder 来实现豪华版、经济版等多种表示。代码示例展示了分离构造与表示的核心思路

#include <string>
#include <memory>
#include <iostream>struct Car {std::string engine;std::string wheels;std::string body;std::string color;void show() const {std::cout << "Engine: " << engine << ", Wheels: " << wheels<< ", Body: " << body << ", Color: " << color << std::endl;}
};// 抽象建造者
class CarBuilder {
public:virtual ~CarBuilder() = default;virtual void buildEngine() = 0;virtual void buildWheels() = 0;virtual void buildBody() = 0;virtual void setColor() = 0;virtual std::unique_ptr<Car> getResult() = 0;
};// 具体建造者:经济版
class EconomyCarBuilder : public CarBuilder {std::unique_ptr<Car> car_;
public:EconomyCarBuilder(): car_(std::make_unique<Car>();) {}void buildEngine() override { car_->engine = "1.6L"; }void buildWheels() override { car_->wheels = "15inch"; }void buildBody() override { car_->body = "Compact"; }void setColor() override { car_->color = "Blue"; }std::unique_ptr<Car> getResult() override { return std::move(car_); }
};// 具体建造者:豪华版
class LuxuryCarBuilder : public CarBuilder {std::unique_ptr<Car> car_;
public:LuxuryCarBuilder(): car_(std::make_unique<Car>();) {}void buildEngine() override { car_->engine = "4.0L V8"; }void buildWheels() override { car_->wheels = "20inch"; }void buildBody() override { car_->body = "CarbonFiber"; }void setColor() override { car_->color = "Red"; }std::unique_ptr<Car> getResult() override { return std::move(car_); }
};// Director:负责按顺序调用构造方法
class Director {
public:// 统一的构造流程void construct(CarBuilder& builder) {builder.buildEngine();builder.buildWheels();builder.buildBody();builder.setColor();}
};// 客户端示例
int main() {Director director;EconomyCarBuilder econBuilder;director.construct(econBuilder);auto econCar = econBuilder.getResult();econCar->show();LuxuryCarBuilder luxBuilder;director.construct(luxBuilder);auto luxCar = luxBuilder.getResult();luxCar->show();return 0;
}

3.3 代码要点解析与扩展路径

Product 封装策略强调将部件信息集中到 Car 结构中,便于后续扩展新部件或新表示时的维护。若需要更复杂的表达,可以将 Car 拆分为子对象并在 show() 或输出接口中汇总信息。

Builder 与 Director 的解耦体现了“调用者不直接参与部件拼接”的设计原则。通过扩展新的 ConcreteBuilder,可以实现不同配置的车辆表示,而无需修改客户端代码。

广告

后端开发标签