通过“对象创建” 模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
一、动机
-
在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
-
如何应对这种变化?如何提供一种 “封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?
二、模式定义
将一个复杂对象的构建与其表示相分离,使得同样的构建过
程(稳定)可以创建不同的表示(变化)。
——《设计模式》GoF
三、代码示例
我们以房屋为例来展示建造者模式的应用。House
类代表房屋对象,而HouseBuilder
抽象类定义了构建房屋的步骤。StoneHouseBuilder
是HouseBuilder
的具体实现,用于构建石头房屋。HouseDirector
类负责指导具体建造者对象的构建过程。
通过使用建造者模式,我们可以将房屋对象的构建逻辑与客户端代码分离开来。客户端只需要创建一个合适的具体建造者对象,并将其传递给指导者进行构建。这样可以使客户端代码更简洁、可读性更高,并且在需要构建不同类型的房屋时更加灵活和扩展。
#include <iostream>class House {
public:void SetFoundation(const std::string& foundation) {this->foundation = foundation;}void SetWalls(const std::string& walls) {this->walls = walls;}void SetRoof(const std::string& roof) {this->roof = roof;}void SetDoors(const std::string& doors) {this->doors = doors;}void SetWindows(const std::string& windows) {this->windows = windows;}void Show() {std::cout << "房屋部分:" << std::endl;std::cout << "地基:" << foundation << std::endl;std::cout << "墙壁:" << walls << std::endl;std::cout << "屋顶:" << roof << std::endl;std::cout << "门:" << doors << std::endl;std::cout << "窗户:" << windows << std::endl;}private:std::string foundation; // 地基std::string walls; // 墙壁std::string roof; // 屋顶std::string doors; // 门std::string windows; // 窗户
};class HouseBuilder {
public:virtual ~HouseBuilder() {}House* GetResult() {return pHouse;}virtual void BuildFoundation() = 0; // 构建地基virtual void BuildWalls() = 0; // 构建墙壁virtual void BuildRoof() = 0; // 构建屋顶virtual void BuildDoors() = 0; // 构建门virtual void BuildWindows() = 0; // 构建窗户protected:House* pHouse;
};class StoneHouseBuilder : public HouseBuilder {
public:StoneHouseBuilder() {pHouse = new House();}void BuildFoundation() override {pHouse->SetFoundation("石头地基");}void BuildWalls() override {pHouse->SetWalls("石头墙壁");}void BuildRoof() override {pHouse->SetRoof("石头屋顶");}void BuildDoors() override {pHouse->SetDoors("木门");}void BuildWindows() override {pHouse->SetWindows("玻璃窗户");}
};class HouseDirector {
public:HouseDirector(HouseBuilder* builder) {pHouseBuilder = builder;}House* Construct() {pHouseBuilder->BuildFoundation(); // 构建地基pHouseBuilder->BuildWalls(); // 构建墙壁pHouseBuilder->BuildRoof(); // 构建屋顶pHouseBuilder->BuildDoors(); // 构建门pHouseBuilder->BuildWindows(); // 构建窗户return pHouseBuilder->GetResult();}private:HouseBuilder* pHouseBuilder;
};int main() {HouseBuilder* builder = new StoneHouseBuilder(); // 使用石头房屋构建器HouseDirector director(builder);House* house = director.Construct(); // 构建房屋house->Show(); // 展示房屋部分delete house;delete builder;return 0;
}
输出:
房屋部分:
地基:石头地基
墙壁:石头墙壁
屋顶:石头屋顶
门:木门
窗户:玻璃窗户
这时候,假如我们有新需求,需要造一个黄金打造的房子,这时候就很方便了,只需要增加GoldenHouseBuilder
建造器,就可以完成这个扩展,不需要更改以前的代码,满足开放-封闭原则
class GoldenHouseBuilder : public HouseBuilder {
public:GoldenHouseBuilder() {pHouse = new House();}void BuildFoundation() override {pHouse->SetFoundation("黄金地基");}void BuildWalls() override {pHouse->SetWalls("黄金墙壁");}void BuildRoof() override {pHouse->SetRoof("黄金屋顶");}void BuildDoors() override {pHouse->SetDoors("金门");}void BuildWindows() override {pHouse->SetWindows("钻石窗户");}
};
调用过程
HouseBuilder* goldenBuilder = new GoldenHouseBuilder(); // 使用黄金房屋构建器HouseDirector goldenDirector(goldenBuilder);House* goldenHouse = goldenDirector.Construct(); // 构建黄金房屋goldenHouse->Show(); // 展示黄金房屋部分delete goldenHouse;delete goldenBuilder;
房屋部分:
地基:黄金地基
墙壁:黄金墙壁
屋顶:黄金屋顶
门:金门
窗户:钻石窗户
四、结构
五、总结
在软件开发过程中,有时候需要构建具有复杂结构的对象。如果直接在客户端代码中创建和配置这些对象,会导致代码变得复杂且难以维护。此外,如果要构建多个具有不同配置的相似对象,每次都重复编写相似的构建代码也是低效的。为了解决这些问题,可以使用建造者模式。
建造者模式的核心思想是将对象的构建过程从其表示中分离出来。它允许你使用相同的构建过程来创建不同的表示形式。该模式将对象的构建委托给一个单独的建造者对象,该对象负责构建对象的各个部分,并最后返回构建好的对象。
在示例代码中,我们以房屋为例来展示建造者模式的应用。House
类代表房屋对象,而HouseBuilder
抽象类定义了构建房屋的步骤。StoneHouseBuilder
和GoldenHouseBuilder
是HouseBuilder
的具体实现,分别用于构建石头房屋和黄金房屋。HouseDirector
类负责指导具体建造者对象的构建过程。
通过使用建造者模式,我们可以将房屋对象的构建逻辑与客户端代码分离开来。客户端只需要创建一个合适的具体建造者对象,并将其传递给指导者进行构建。这样可以使客户端代码更简洁、可读性更高,并且在需要构建不同类型的房屋时更加灵活和扩展。
建造者模式适用于构建复杂对象的情况,将构建逻辑与表示分离,使得构建过程更加灵活和可扩展。它提供了一种组织和管理对象构建的方式,避免了繁琐和重复的构建代码。通过委托具体的建造者对象来构建对象,客户端代码可以专注于高级操作,而无需关心对象的内部构建细节。