生成器(建造者)模式

生成器是一种创建型设计模式, 当构建一个复杂对象时,将构建过程与表示分离。使得同样的过程创建不同的对象。生成器与其他创建型模式不同, 生成器不要求产品拥有通用接口。 这使得用相同的创建过程生成不同的产品成为可能。

  1. 生成器 (Builder) 接口声明在所有类型生成器中通用的产品构造步骤,一般都由虚函数组成。
  2. 具体生成器 (Concrete Builders) 提供构造过程的不同实现。 具体生成器也可以构造不遵循通用接口的产品。
  3. 产品 (Products) 是最终生成的对象。 由不同生成器构造的产品无需属于同一类层次结构或接口。
  4. 主管 (Director) 类定义调用构造步骤的顺序, 这样你就可以创建和复用特定的产品配置。
  5. 客户端 (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);
}




参考:

https://www.guyuehome.com/37109

posted @   double64  阅读(91)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示