《C++设计模式》生成器模式
文章目录
- 1、简介
- 2、生成器模式介绍
- 2.1 代码示例
- 2.2 组成部分
- 2.3 优缺点
- 2.4 应用场景
- 3、面试常问问题
- 3.1、概念理解
- 3.2、应用场景
- 3.3、实现细节
- 3.4、优缺点分析
- 4、总结
- 5、参考文章
1、简介
生成器模式也有称为建造者模式。生成器模式的意图在于 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示(GoF)。在软件设计中,有时候面临着一个非常复杂的对象的创建工作。这个复杂的对象通常可以分成几个较小的部分,由各个子对象组合出这个复杂对象的过程相对来说比较稳定,但是子对象的创建过程各不相同并且可能面临变化。根据OOD中的OCP原则,我们自然应该对这些子对象的创建过程进行变化封装。
这就是生成器模式的思路。定义一个抽象的建造者的角色(Builder),规定所有具体的建造者都应该具有的功能——这些功能就是如何创建复杂对象的某个特定部分(子对象),而具体如何创建子对象有具体的创建者实现。再定义一个指导者的角色,它把创建者作为工具,知道如何使用这个工具来创建复杂对象。这样,客户在需要创建这个复杂对象的时候,只需要给指导者一个具体的创建者就可以了。至于具体创建者如何创建子对象的细节以及这些子对象之间的差异,不是指导者,也不是客户关心的。
2、生成器模式介绍
生成器模式是一种对象构建模式,旨在通过一步一步构建复杂对象来创建对象。该模式的核心思想是将对象的构建和表示分离,使得相同的构建过程可以创建不同的表示形式。通过这种模式,客户端无需知道复杂对象的内部组成部分与装配方式,只需知道所需建造者的类型即可。
2.1 代码示例
#include <iostream>
#include <string>
#include <memory>
// 产品类
class Product {
private:
std::string part1_;
std::string part2_;
public:
void setPart1(const std::string& part1) {
part1_ = part1;
}
void setPart2(const std::string& part2) {
part2_ = part2;
}
void show() const {
std::cout << "Part 1: " << part1_ << std::endl;
std::cout << "Part 2: " << part2_ << std::endl;
}
};
// 建造者接口
class Builder {
public:
virtual void buildPart() = 0;
virtual std::unique_ptr<Product> getResult() = 0;
virtual ~Builder() = default;
};
// 具体建造者类
class ConcreteBuilder : public Builder {
private:
std::unique_ptr<Product> product_;
public:
ConcreteBuilder() : product_(std::make_unique<Product>()) {}
void buildPart() override {
product_->setPart1("Part 1 built by ConcreteBuilder");
product_->setPart2("Part 2 built by ConcreteBuilder");
}
std::unique_ptr<Product> getResult() override {
return std::move(product_);
}
};
// 指挥者类
class Director {
private:
Builder* builder_;
public:
explicit Director(Builder* builder) : builder_(builder) {}
void construct() {
builder_->buildPart();
}
};
// 客户端代码
int main() {
ConcreteBuilder builder;
Director director(&builder);
director.construct();
std::unique_ptr<Product> product = builder.getResult();
product->show();
return 0;
}
2.2 组成部分
(1)生成器(Builder):定义一个抽象接口,以规范产品对象的各个组成部分的建造。这个接口通常包含多个抽象方法,用于逐步构建复杂对象。
(2)具体生成器(ConcreteBuilder):实现Builder接口,以构造和组装产品的各个部分。具体生成器类还需要跟踪其创建的表示形式,并提供一个方法来获取最终构建的产品对象。
(3)指挥者(Director):定义一个用于构建对象的算法。它并不直接构建对象,而是调用Builder接口的方法来构建和装配对象。指挥者类使得构建过程更加灵活和可控。
(4)产品(Product):表示正在构建的复杂对象。它通常包含多个组成部分,这些部分由Builder类来构建和装配。
2.3 优缺点
优点:
(1)易于维护:由于建造者模式将产品的构建过程封装在建造者和指挥者中,因此当产品需要更改时,只需要修改相应的建造者类即可。
(2)易于扩展:通过增加新的具体建造者类,可以很容易地扩展系统以创建新类型的产品。
(3)灵活性高:建造者模式允许通过不同的具体建造者来创建不同的产品表示,从而提高了系统的灵活性。
缺点:
(1)代码复杂度增加:由于引入了多个类(抽象建造者、具体建造者、指挥者等),会导致代码结构相对复杂。
(2)需要额外的代码维护成本:增加的类和它们之间的关系需要更多的代码来维护,特别是当产品的结构或构建过程发生变化时,可能需要修改多个类的代码。
2.4 应用场景
建造者模式适用于以下场景:
(1)当需要创建一个复杂对象,且这个对象包含多个部件或属性时。
(2)当对象的构建过程需要遵循特定的顺序或步骤时。
(3)当需要创建多个类似对象,但它们的构建过程大部分相同,只有部分细节不同时。
(4)当需要复用构建过程,但每次构建的产品可能有所不同时。
3、面试常问问题
关于建造者模式(Builder Pattern),面试中可能会遇到以下高频问题:
3.1、概念理解
(1)什么是建造者模式?
建造者模式是一种创建型设计模式,它将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式通常包括四个角色:抽象建造者(Builder)、具体建造者(ConcreteBuilder)、指挥者(Director)和产品(Product)。
(2)建造者模式和工厂模式有什么区别?
工厂模式主要提供创建单个类产品的接口,而建造者模式则更加关注于复杂对象的创建过程,它将各种产品集中起来进行管理,用来创建具有不同属性的产品。此外,建造者模式还关注零件装配的顺序,而工厂模式则主要关注对象的创建。
3.2、应用场景
(1)建造者模式适用于哪些场景?
建造者模式适用于需要生成的对象具有复杂的内部结构和内部属性本身相互依赖的场景。例如,一个汽车对象可能包含许多部件,如车轮、方向盘、发动机等,这些部件的装配过程复杂且需要一定的顺序,这时就可以使用建造者模式来创建汽车对象。
(2)能否给出一个建造者模式的具体应用场景?
一个常见的应用场景是创建具有不同配置的复杂对象,如电脑配置。不同的用户可能需要不同的硬件配置,如CPU、内存、硬盘等。通过建造者模式,可以轻松地创建具有不同配置的电脑对象,而无需修改现有的代码。
3.3、实现细节
(1)在建造者模式中,指挥者(Director)的作用是什么?
指挥者(Director)在建造者模式中起到管理建造者的作用。它调用具体建造者来创建复杂对象的各个部分,并确保对象各部分的完整创建或按某种顺序创建。指挥者不涉及具体产品的信息,只负责协调建造过程。
(2)建造者模式中的抽象建造者(Builder)和具体建造者(ConcreteBuilder)有什么区别?
抽象建造者(Builder)给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定了要实现复杂对象的哪些部分的创建,但并不涉及具体的对象部件的创建。而具体建造者(ConcreteBuilder)则实现了Builder接口,并针对不同的商业逻辑,具体化复杂对象的各部分的创建。在建造过程完成后,具体建造者提供产品的实例。
3.4、优缺点分析
(1)建造者模式的优点是什么?
建造者模式的优点包括:
可以使客户端代码与产品的具体表示分离,使得同样的构建过程可以创建不同的表示。
易于扩展和维护,因为可以在不修改现有代码的情况下添加新的具体建造者。
可以控制对象的创建过程,确保对象各部分的完整性和正确性。
(2)建造者模式的缺点是什么?
建造者模式的缺点包括:
如果产品的内部变化复杂,可能会导致建造者接口变得庞大和难以维护。
在某些情况下,如果只需要创建简单对象,使用建造者模式可能会增加不必要的复杂性。
通过以上问题的回答,可以全面展示对建造者模式的理解和应用能力。在面试中,可以结合具体的应用场景和代码实现来展示对建造者模式的掌握程度。
4、总结
综上所述,生成器设计模式是一种强大的创建型设计模式,它通过将复杂对象的构建过程与表示分离,提供了更灵活和可控的对象创建方式。然而,它也有其局限性,如使用范围受限和系统可能变得庞大等。因此,在选择是否使用生成器模式时,需要仔细权衡其优缺点以及具体的应用场景。
5、参考文章
5.1 C++开发者必备:23种设计模式全面解析