生成器(建造者)模式
生成器是一种创建型设计模式, 当构建一个复杂对象时,将构建过程与表示分离。使得同样的过程创建不同的对象。生成器与其他创建型模式不同, 生成器不要求产品拥有通用接口。 这使得用相同的创建过程生成不同的产品成为可能。
- 生成器 (Builder) 接口声明在所有类型生成器中通用的产品构造步骤,一般都由虚函数组成。
- 具体生成器 (Concrete Builders) 提供构造过程的不同实现。 具体生成器也可以构造不遵循通用接口的产品。
- 产品 (Products) 是最终生成的对象。 由不同生成器构造的产品无需属于同一类层次结构或接口。
- 主管 (Director) 类定义调用构造步骤的顺序, 这样你就可以创建和复用特定的产品配置。
- 客户端 (Client) 必须将某个生成器对象与主管类关联。 一般情况下, 你只需通过主管类构造函数的参数进行一次性关联即可。 此后主管类就能使用生成器对象完成后续所有的构造任务。
我们可以看到生成器执行了单一职责原则,可以将复杂构造代码从产品的业务逻辑中分离出来。和工厂模式类似的是,生成器模式也是采用来生成器和具体生成器来构建不同实现。但是不同的是工厂模式是通过工厂来对具体操作统一管理,但是在生成器中不同的设计了主管(Director)来构建步骤顺序。
生成器模式模板
示例:
#include <iostream>
#include <vector>
#include <string>
// 拿到的产品类
class Product1 {
public:
std::vector<std::string> parts_;
void ListParts()const {
std::cout << "Product parts: ";
for (size_t i = 0; i<parts_.size(); i++) {
if (parts_[i] == parts_.back()) {
std::cout << parts_[i];
}
else {
std::cout << parts_[i] << ", ";
}
}
std::cout << "\n\n";
}
};
// 生成器,一般存放一些通用的产品步骤
class Builder {
public:
virtual ~Builder() {}
virtual void ProducePartA() const = 0;
virtual void ProducePartB() const = 0;
virtual void ProducePartC() const = 0;
};
// 具体生成器,可以看到上述虚函数的实例化
class ConcreteBuilder1 : public Builder {
private:
Product1* product;
public:
ConcreteBuilder1() {
this->Reset();
}
~ConcreteBuilder1() {
delete product;
}
void Reset() {
this->product = new Product1();
}
/**
* 所有生产步骤都使用同一个产品实例
*/
void ProducePartA()const override {
this->product->parts_.push_back("PartA1");
}
void ProducePartB()const override {
this->product->parts_.push_back("PartB1");
}
void ProducePartC()const override {
this->product->parts_.push_back("PartC1");
}
// 通过GetProduct 拿到不同步骤的执行的结果
Product1* GetProduct() {
Product1* result = this->product;
this->Reset();
return result;
}
};
// 定义了不同的生成方式
class Director {
/**
* @var Builder
*/
private:/*decltype*/
Builder* builder;
public:
void set_builder(Builder* builder) {
this->builder = builder;
}
void BuildMinimalViableProduct() {
this->builder->ProducePartA();
}
void BuildFullFeaturedProduct() {
this->builder->ProducePartA();
this->builder->ProducePartB();
this->builder->ProducePartC();
}
};
// client 可以放在一个函数中,也可以写在main函数中
void ClientCode(Director& director)
{
ConcreteBuilder1* builder = new ConcreteBuilder1();
director.set_builder(builder);
std::cout << "Standard basic product:\n";
director.BuildMinimalViableProduct();
Product1* p = builder->GetProduct();
p->ListParts();
delete p;
std::cout << "Standard full featured product:\n";
director.BuildFullFeaturedProduct();
p = builder->GetProduct();
p->ListParts();
delete p;
// 当然构建器模式也可以在没有Director类的情况下使用。
std::cout << "Custom product:\n";
builder->ProducePartA();
builder->ProducePartC();
p = builder->GetProduct();
p->ListParts();
delete p;
delete builder;
}
int main() {
Director* director = new Director();
ClientCode(*director);
delete director;
getchar();
return 0;
}
输出:
Standard basic product:
Product parts: PartA1
Standard full featured product:
Product parts: PartA1, PartB1, PartC1
Custom product:
Product parts: PartA1, PartC1
从引用类到引用函数
这个还没看,先贴在这里:
constexpr int kMathEpsilon = 0;
template <class ElemType>
SeqList<ElemType>::SeqList(ElemType v[], int n, int size) //构造函数
{
elems = new ElemType[size];
assert(elems);
maxLength = size;
length = n;
for (int i = 0; i < length; i++)
elems[i] = v[i];
}
// 函数作为参数传入,一般使用函数指针
// https://www.jianshu.com/p/974540146931
// int *func(int a, int b) ; //这个声明的是一个函数
// int (*func)(int a, int b); //这个声明的是一个指针变量
template <class ElemType>
void SeqList<ElemType>::Traverse(void(*visit)(const ElemType &)) const//引用函数,函数指向指针
{
for (int i = 0; i < length; i++)
{
visit(elems[i]);
}
}
template <class ElemType>
void Write(const ElemType &e)
{
// 用decltype
// https://blog.csdn.net/u014609638/article/details/106987131/
// 声明了一个函数类型
//using FuncType = int(int &, const ElemType &);
//FuncType *pf = add_to;
decltype(add_to) *pf = add_to;
pf(2, e);
}
int add_to(int &des, const ElemType &e)
{
cout << e << " ";
}
void main() {
int a[] = { 1,2,3 };
SeqList<int> la(a, 3, 5);
la.Traverse(Write);
}
参考:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了