设计模式12-构建器
- 由来和动机
- 原理思想
- 构建器模式的C++代码实现
- 构建器模式中的各个组件详解
- 1. 产品类(Product)
- 2. 构建类(Builder)
- 3. 具体构建类(ConcreteBuilder)
- 4. 指挥者类(Director)
- 各个类的相互关系
- 示例运行
- 特点及其应用
- 总结
- 问题
- 解答
- 模板方法模式(Template Method Pattern)
- 构造者模式(Builder Pattern)
- 主要区别
- 为什么构造者模式不能完全替代模板方法模式
- 结论
构建器模式(Builder Pattern)是一种设计模式,主要用于分步骤创建一个复杂的对象。这种模式的主要动机是将一个复杂对象的构建过程与其表示相分离,使得同样的构建过程可以创建不同的表示。构建器模式特别适合创建那些包含很多子对象或者配置步骤的对象。构建器模式也是对象创建模式的一种。
由来和动机
- 在软件系统中有时候面临着一个复杂对象的创建工作。通常由各个部分的子对象用一定的算法构成。由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化但是将他们组合在一起的算法却相对稳定。
- 那么如何应对这种变化呢?如何提供一种封装机制来隔离除复杂对象的各个部分的变化?从而保持系统中的稳定,构建算法不随着需求的变化而变化。构建器模式就是为了解决这个问题而诞生的一种模式。构建器模式的动机就是将对象的创建过程分解为多个步骤,并通过一个构建器对象来逐步构建最终的复杂对象。
原理思想
构建器模式的核心思想是将对象的构建过程封装在一个独立的构建器对象中。构建器对象提供了一系列方法,用于设置对象的各个部分。最后,通过一个build()
方法来返回最终的复杂对象。这种方式不仅使对象的构建过程清晰易懂,还使得不同的构建器可以创建不同类型的对象。
构建器模式的C++代码实现
下面是一个详细的C++代码示例,演示如何使用构建器模式来构建一个复杂的对象。
#include <iostream>
#include <string>// 产品类
class Product {
public:void setPartA(const std::string& partA) { partA_ = partA; }void setPartB(const std::string& partB) { partB_ = partB; }void setPartC(const std::string& partC) { partC_ = partC; }void show() const {std::cout << "Product parts: " << partA_ << ", " << partB_ << ", " << partC_ << std::endl;}
private:std::string partA_;std::string partB_;std::string partC_;
};// 构建器基类
class Builder {
public:virtual ~Builder() {}virtual void buildPartA() = 0;virtual void buildPartB() = 0;virtual void buildPartC() = 0;virtual Product* getResult() = 0;
};// 具体构建器
class ConcreteBuilder : public Builder {
public:ConcreteBuilder() { product_ = new Product(); }~ConcreteBuilder() { delete product_; }void buildPartA() override { product_->setPartA("PartA"); }void buildPartB() override { product_->setPartB("PartB"); }void buildPartC() override { product_->setPartC("PartC"); }Product* getResult() override { return product_; }
private:Product* product_;
};// 指挥者类
class Director {
public:void setBuilder(Builder* builder) { builder_ = builder; }Product* construct() {builder_->buildPartA();builder_->buildPartB();builder_->buildPartC();return builder_->getResult();}
private:Builder* builder_;
};int main() {Director director;ConcreteBuilder builder;director.setBuilder(&builder);Product* product = director.construct();product->show();delete product; // 需要记得删除Product对象以避免内存泄漏return 0;
}
构建器模式中的各个组件详解
在构建器模式中,主要包括以下四个角色:产品类、构建类(抽象构建器)、具体构建类和指挥者类。下面是对每个角色的详细说明。
1. 产品类(Product)
作用:产品类是要构建的复杂对象。它包含多个组成部分,这些部分可以通过构建器来逐步设置。
结构:产品类包含表示最终复杂对象的各个部分(通常是成员变量),以及设置这些部分的方法。
示例代码:
// 产品类
class Product {
public:void setPartA(const std::string& partA) { partA_ = partA; }void setPartB(const std::string& partB) { partB_ = partB; }void setPartC(const std::string& partC) { partC_ = partC; }void show() const {std::cout << "Product parts: " << partA_ << ", " << partB_ << ", " << partC_ << std::endl;}
private:std::string partA_;std::string partB_;std::string partC_;
};
在这个示例中,Product
类有三个部分(partA_
、partB_
和partC_
),并提供了设置这些部分的方法。
2. 构建类(Builder)
作用:抽象构建器类定义了创建产品各个部分的方法接口,但不实现这些方法。它为具体构建器类提供了一个通用接口。
结构:抽象构建器类通常包含纯虚方法,这些方法用于创建产品的各个部分以及返回最终产品。
示例代码:
// 构建器基类
class Builder {
public:virtual ~Builder() {}virtual void buildPartA() = 0;virtual void buildPartB() = 0;virtual void buildPartC() = 0;virtual Product* getResult() = 0;
};
在这个示例中,Builder
类定义了四个纯虚方法,用于创建产品的各个部分和获取最终产品。
3. 具体构建类(ConcreteBuilder)
作用:具体构建器类实现了抽象构建器类定义的所有方法。它负责具体创建产品的各个部分,并返回最终产品。
结构:具体构建器类通常包含一个产品对象,并通过实现构建器接口的方法来设置产品的各个部分。
示例代码:
// 具体构建器
class ConcreteBuilder : public Builder {
public:ConcreteBuilder() { product_ = new Product(); }~ConcreteBuilder() { delete product_; }void buildPartA() override { product_->setPartA("PartA"); }void buildPartB() override { product_->setPartB("PartB"); }void buildPartC() override { product_->setPartC("PartC"); }Product* getResult() override { return product_; }
private:Product* product_;
};
在这个示例中,ConcreteBuilder
类实现了所有抽象构建器的方法,并在构建产品的过程中设置产品的各个部分。
4. 指挥者类(Director)
作用:指挥者类负责控制构建过程。它按照一定的顺序调用构建器的方法来创建产品。
结构:指挥者类通常包含一个构建器对象,并提供一个方法来执行产品的构建过程。
示例代码:
// 指挥者类
class Director {
public:void setBuilder(Builder* builder) { builder_ = builder; }Product* construct() {builder_->buildPartA();builder_->buildPartB();builder_->buildPartC();return builder_->getResult();}
private:Builder* builder_;
};
在这个示例中,Director
类通过调用构建器的方法来构建产品,并返回最终的产品。
各个类的相互关系
- 产品类(Product):包含复杂对象的各个部分,并提供设置和显示这些部分的方法。
- 构建类(Builder):定义了创建产品各个部分的方法接口。
- 具体构建类(ConcreteBuilder):实现了抽象构建器类的方法,负责具体创建产品的各个部分。
- 指挥者类(Director):控制构建过程,通过调用构建器的方法按顺序创建产品。
示例运行
结合以上代码示例,运行以下main
函数会生成并展示一个完整的产品:
int main() {Director director;ConcreteBuilder builder;director.setBuilder(&builder);Product* product = director.construct();product->show();delete product; // 需要记得删除Product对象以避免内存泄漏return 0;
}
运行结果:
Product parts: PartA, PartB, PartC
通过以上详细说明和代码示例,可以清楚地理解构建器模式的结构和作用。构建器模式通过分步骤构建复杂对象,提高了代码的可读性和可维护性,并提供了更大的灵活性来创建不同类型的产品。
特点及其应用
特点:
- 分步骤构建:构建器模式将对象的构建过程分解为一系列步骤,每一步都可以独立进行。
- 可扩展性好:可以通过不同的具体构建器来创建不同的对象。
- 解耦构建过程和表示:构建器模式将对象的构建过程和表示解耦,使得相同的构建过程可以创建不同的表示。
应用场景:
- 复杂对象的创建:当创建一个复杂对象时,需要分步骤进行,而且每一步可能有不同的实现方式。
- 代码可读性和可维护性:当构建逻辑复杂且需要复用时,使用构建器模式可以使代码更清晰和易于维护。
- 配置对象:构建器模式适合用来创建那些包含多个配置项的对象,例如创建一个包含多个选项的配置文件。
总结
构建器模式是一种强大的设计模式,通过将对象的构建过程分离出来,使得复杂对象的创建变得更加灵活和可维护。在C++中,构建器模式可以通过定义一个产品类、一个抽象构建器类、一个具体构建器类以及一个指挥者类来实现。这种模式广泛应用于需要创建复杂对象的场景中,例如GUI库中的窗口构建、报表生成、游戏中的复杂角色创建等。
问题
在应用过程中是不是可以用构造者模式代替模版方法,完成变化与固定步骤的完全分离,如果不行为什么不行?
解答
构造者模式(Builder Pattern)和模板方法模式(Template Method Pattern)都是用于创建和管理对象的行为模式,但它们适用于不同的场景和问题。虽然它们都有助于将变化与固定步骤分离,但它们并不是可以互相替代的,因为它们解决的问题和实现方式不同。下面将详细说明两者的区别以及为什么不能直接用构造者模式代替模板方法模式。
模板方法模式(Template Method Pattern)
作用:模板方法模式定义了一个操作中的算法骨架,而将一些步骤的实现延迟到子类中。模板方法模式使得子类可以在不改变算法结构的情况下重新定义算法的某些步骤。
结构:
- 抽象类:定义了一个模板方法,包含算法的骨架。模板方法调用了若干个抽象操作,这些操作在子类中实现。
- 具体类:实现了抽象类中定义的抽象操作。
示例代码:
#include <iostream>class AbstractClass {
public:void templateMethod() {stepOne();stepTwo();stepThree();}virtual ~AbstractClass() {}protected:virtual void stepOne() = 0;virtual void stepTwo() = 0;virtual void stepThree() = 0;
};class ConcreteClass : public AbstractClass {
protected:void stepOne() override {std::cout << "ConcreteClass: Step One" << std::endl;}void stepTwo() override {std::cout << "ConcreteClass: Step Two" << std::endl;}void stepThree() override {std::cout << "ConcreteClass: Step Three" << std::endl;}
};int main() {ConcreteClass concreteClass;concreteClass.templateMethod();return 0;
}
运行结果:
ConcreteClass: Step One
ConcreteClass: Step Two
ConcreteClass: Step Three
构造者模式(Builder Pattern)
作用:构造者模式将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
结构:
- 产品类:表示要构建的复杂对象。
- 构建类(抽象构建器):定义了创建产品各个部分的方法接口。
- 具体构建类:实现了抽象构建器类的方法,负责具体创建产品的各个部分。
- 指挥者类:控制构建过程,通过调用构建器的方法按顺序创建产品。
示例代码(与之前相同):
// 产品类
class Product {
public:void setPartA(const std::string& partA) { partA_ = partA; }void setPartB(const std::string& partB) { partB_ = partB; }void setPartC(const std::string& partC) { partC_ = partC; }void show() const {std::cout << "Product parts: " << partA_ << ", " << partB_ << ", " << partC_ << std::endl;}
private:std::string partA_;std::string partB_;std::string partC_;
};// 构建器基类
class Builder {
public:virtual ~Builder() {}virtual void buildPartA() = 0;virtual void buildPartB() = 0;virtual void buildPartC() = 0;virtual Product* getResult() = 0;
};// 具体构建器
class ConcreteBuilder : public Builder {
public:ConcreteBuilder() { product_ = new Product(); }~ConcreteBuilder() { delete product_; }void buildPartA() override { product_->setPartA("PartA"); }void buildPartB() override { product_->setPartB("PartB"); }void buildPartC() override { product_->setPartC("PartC"); }Product* getResult() override { return product_; }
private:Product* product_;
};// 指挥者类
class Director {
public:void setBuilder(Builder* builder) { builder_ = builder; }Product* construct() {builder_->buildPartA();builder_->buildPartB();builder_->buildPartC();return builder_->getResult();}
private:Builder* builder_;
};int main() {Director director;ConcreteBuilder builder;director.setBuilder(&builder);Product* product = director.construct();product->show();delete product; // 需要记得删除Product对象以避免内存泄漏return 0;
}
主要区别
-
目的不同:
- 模板方法模式:用于定义一个算法的骨架,并允许子类实现其中的某些步骤。它的核心在于让子类决定某些步骤的具体实现,但算法的整体结构是固定的。
- 构造者模式:用于分步骤创建一个复杂的对象。它的核心在于分离对象的构建过程和表示,使得同样的构建过程可以创建不同的表示。
-
实现方式不同:
- 模板方法模式:通过继承和方法重载实现。抽象类定义算法的骨架,具体类实现具体步骤。
- 构造者模式:通过组合和逐步构建实现。构建器类定义了创建对象的各个部分的方法,指挥者类控制构建过程。
-
应用场景不同:
- 模板方法模式:适用于当一个算法的整体结构固定,但某些步骤的实现可以变化时。常用于框架和库中,定义一些通用算法,让用户实现具体步骤。
- 构造者模式:适用于创建一个复杂对象,其构建过程可以分为多个步骤。常用于需要灵活创建复杂对象的场景。
为什么构造者模式不能完全替代模板方法模式
- 不同的设计意图:模板方法模式的设计意图是通过继承和方法重载来复用算法的整体结构,而构造者模式的设计意图是通过组合和分步骤构建来创建复杂对象。
- 适用场景不同:模板方法模式更适合于算法步骤固定但实现可以变化的场景,而构造者模式更适合于需要逐步创建复杂对象的场景。
- 实现方式不同:模板方法模式依赖于抽象类和具体类的继承关系,而构造者模式依赖于构建器和指挥者的组合关系。
结论
虽然构造者模式和模板方法模式都可以用于将变化与固定步骤分离,但它们的适用场景和实现方式不同,不能简单地互相替代。在设计模式的选择上,应根据具体问题的需求选择合适的模式,而不是试图用一种模式解决所有问题。