设计模式-04 设计模式-Builder

设计模式-04 设计模式-Builder

1.定义

建造者模式(Builder Pattern)是一种创建型设计模式,它允许你使用不同的构建步骤来创建复杂的对象。
建造者模式的定义是:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

                                       指挥者
                                          |
                                     /         \\
                                    /           \\
                                   /             \\
                              具体建造者 A       具体建造者 B
                                   |               |
                                   /               |
                    _______________/_______________|______________
                   |                                              |
                   |                                              |
                   |                                              |
            _______|______________________________________________|____
            |                                                          |
            |                      已构建的产品                         |
            |__________________________________________________________|

在这个 ASCII 图中:

  • 指挥者负责协调建造过程,它告诉建造者要创建哪些部分以及如何组装它们。
  • 具体建造者代表不同的产品类型或变体。每个具体建造者负责构建产品的一个或多个部分。
  • 已构建的产品是建造过程的结果。

建造过程如下:

  1. 指挥者创建一个具体建造者。
  2. 指挥者调用具体建造者的构建方法来创建产品的不同部分。
  3. 指挥者可以调用多个具体建造者来创建复杂的产品结构。
  4. 一旦所有部分都构建完成,指挥者调用具体建造者的获取产品方法来检索已构建的产品。
2.内涵


换句话说,建造者模式将对象的构建过程与对象的表示分离。这使得你可以使用相同的构建过程来创建不同类型的对象,而无需更改构建代码本身。

建造者模式包含以下角色:

  • 建造者(Builder):负责创建和组装最终的对象。
  • 具体建造者(Concrete Builder):实现建造者接口,并负责创建和组装最终对象的特定部分。
  • 指挥者(Director):负责协调建造过程,它告诉建造者要创建哪些部分以及如何组装它们。
  • 产品(Product):最终创建的对象。
3.案例对比

不用 Builder 设计模式

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <fstream>
#include <tuple>
#include <sstream>
#include <memory>
using namespace std;

/**
 *  <p>hello</p>
    <ul> <li>hello</li> <li>world</li></ul>
 * @return
 */
int main() {

    auto text= "hello";
    string output;
    output+="<p>";
    output+=text;
    output+="</p>";

    cout<<output<<endl;

    string words[] = {"hello", "world"};
    ostringstream oss;
    oss<<"<ul>";
    for(auto w: words){
        oss<<" <li>" << w <<"</li>";
    }
    oss<<"</ul>";
    cout<<oss.str()<<endl;


    return 0;
}


使用 Builder 设计模式

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <fstream>
#include <tuple>
#include <sstream>
#include <memory>
using namespace std;


struct HtmlElement
{
    string name, text;
    vector<HtmlElement> elements;
    const size_t indent_size =2;

    HtmlElement(){}
    HtmlElement(const string& name,const string& text):name(name),text(text){}

    string str(int intent = 0)const{
        ostringstream oss;
        string i(indent_size*intent, ' ');
        oss << i << "<" << name << ">" << endl;


        if(text.size() > 0){
            oss<<string(indent_size*(intent + 1), ' ') << text <<endl;
        }

        for(const auto& e:elements) {
            oss << e.str(intent + 1);
        }
        oss<<i << "</" << name << ">" << endl;
        return oss.str();
    }

};

struct HtmlBuilder
{
    HtmlElement root;
    HtmlBuilder(string rootname){
        root.name = rootname;
    }

    void add_child(string child_name, string child_text){
        HtmlElement e{child_name, child_text};
        root.elements.emplace_back(e);
    }

    string str() const {return root.str();}
};

int main() {
    HtmlBuilder builder ("ul");
    builder.add_child("li", "hello");
    builder.add_child("li", "world");
    builder.add_child("li", "hello");

    cout << builder.str() << endl;
    return 0;
}

4.注意事项

在实际使用建造者模式时,需要注意以下几点和原则:

1. 分离接口和实现

建造者模式的核心原则是将对象的构建过程与它的表示分离。因此,建造者接口应该只定义创建和组装对象所需的方法,而具体的实现细节应该委托给具体建造者。

2. 确保建造者产品的一致性

指挥者负责协调建造过程,它告诉建造者要创建哪些部分以及如何组装它们。为了确保建造出的产品是一致的,指挥者需要使用相同的建造者接口来调用所有具体建造者。

3. 灵活性和可扩展性

建造者模式的优点之一是它的灵活性和可扩展性。你可以轻松地添加新的具体建造者来创建新的对象类型,而无需修改现有代码。这使得建造者模式非常适合需要创建各种不同对象的场景。

4. 避免创建不必要的具体建造者

虽然建造者模式允许你创建任意数量的具体建造者,但重要的是要避免创建不必要的具体建造者。每个具体建造者都应该代表一种不同的对象类型或变体。

5. 考虑使用不可变对象

对于需要不可变对象的场景,你可以考虑使用不可变对象来表示产品。这可以防止在构建过程之后意外修改对象。

6. 性能考虑

如果性能是一个问题,你需要仔细考虑建造者模式的开销。创建和销毁大量的具体建造者可能会对性能产生影响。

7. 何时使用建造者模式

建造者模式最适合用于创建复杂的对象,这些对象需要经过多个构建步骤才能创建。例如,它可以用在创建文档、GUI 控件或 Web 页面等对象中。


个人觉得如果对象很简单,并且不需要经过多个构建步骤,则建造者模式可能过于复杂。在这种情况下,可以使用更简单的创建模式,例如工厂方法模式或单例模式会更简单。


5.最佳实践


建造者模式的最佳实践包括:

  • 使用不可变对象:对于需要不可变对象的场景,使用不可变对象来表示产品可以防止在构建过程之后意外修改对象。
  • 使用分层建造者:对于复杂的对象,可以考虑使用分层建造者。分层建造者将构建过程分解成更小的步骤,并允许你创建嵌套的对象结构。
  • 使用流式 API:对于需要创建大量相似对象的场景,可以使用流式 API 来简化构建过程。流式 API 允许你将构建步骤链接在一起,并使用链式语法来创建对象。
  • 考虑使用生成器函数:在某些情况下,使用生成器函数可以简化建造者模式的实现。生成器函数可以让你一步一步地构建对象,而无需显式地创建和销毁具体建造者。
  • 避免创建不必要的具体建造者:每个具体建造者都应该代表一种不同的对象类型或变体。避免创建不必要的具体建造者,因为这会增加代码的复杂性和维护成本。
  • 确保建造者产品的一致性:指挥者负责协调建造过程,它告诉建造者要创建哪些部分以及如何组装它们。为了确保建造出的产品是一致的,指挥者需要使用相同的建造者接口来调用所有具体建造者。
6.总结

如果性能是一个问题,你需要仔细考虑建造者模式的开销。创建和销毁大量的具体建造者可能会对性能产生影响。

  • 36
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值