建造者模式(创建型)

建造者模式


建造者模式又称为生成器模式,是一种对象创建型模式,它将客户端与包含多个组成部分或部件的复杂对象的创建过程解耦,客户端无需知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。具体的建造者关注如何一步一步创建一个复杂对象,不同的具体创建者定义不同的创建过程,且它们之间相互独立,增加新的建造者非常方便,无需修改已有代码,系统扩展性好。

意图

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

参与者

  • Builder
    为创建一个Product对象的各个部件指定抽象接口

  • Concrete Builer
    实现Builder的接口以构造和装配该产品的各个部件;
    定义并明确它所创建的表示;
    提供一个检索产品的接口

  • Director
    构造一个使用Builder接口的对象

  • Product
    表示被构造的复杂对象,Concrete Builder 创建该产品的内部表示并定义它的装配过程;
    包含定义组成部件的类,包括将这些部件装配成最终产品的接口

模式结构

  • 基本的模式结构图
    builder

  • 各个参与者的协作图
    builder_corp

代码实现

  1. 首先定义抽象产品类,包括AddPart()ShowProduct()分别定义组成Product的各个部分
    及显示产品:

    1
    2
    3
    4
    5
    6
    class AbstractProduct
    {
    public:
    virtual void AddPart(const char* part) = 0; //产品的部件操作接口
    virtual void ShowProduct() = 0; // 打印显示产品
    };
  2. 再定义两个具体的产品ProductA、ProductB,并实现各自的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    // Product A
    class ProductA: public AbstractProduct
    {
    private:
    vector<const char*> m_VecPart;
    public:
    void AddPart(const char *part)
    {
    m_VecPart.push_back(part);
    }
    void ShowProduct()
    {
    cout << "I am Product A!" << endl;
    for (vector<const char*>::iterator it = m_VecPart.begin(); it != m_VecPart.end(); ++it)
    {
    cout << *it << endl;
    }
    }
    };

    // Product B
    class ProductB: public AbstractProduct
    {
    private:
    vector<const char*> m_VecPart;
    public:
    void AddPart(const char *part)
    {
    m_VecPart.push_back(part);
    }
    void ShowProduct()
    {
    cout << "I am Product B!" << endl;
    for (vector<const char*>::iterator it = m_VecPart.begin(); it != m_VecPart.end(); ++it)
    {
    cout << *it << endl;
    }
    }
    };

  3. 定义抽象的Builder类:

    1
    2
    3
    4
    5
    6
    7
    class AbstractBuilder
    {
    public:
    virtual void BuilderPart1() = 0; // 构建产品部件1
    virtual void BuilderPart2() = 0; // 构建产品部件2
    virtual AbstractProduct* GetProduct() = 0; // 获取构建的产品
    };
  4. 定义具体两个Builder,BuilderA及BuilderB 分别构建和组装产品A和B:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    // Builder A
    class BuilderA: public AbstractBuilder //构建产品A内部部分
    {
    private:
    AbstractProduct *m_pProduct; // 被构建的抽象产品指针
    public:
    BuilderA()
    {
    m_pProduct = new ProductA(); //构建产品A
    }
    void BuilderPart1()
    {
    m_pProduct->AddPart("A Part 1 is Completed!");
    }
    void BuilderPart2()
    {
    m_pProduct->AddPart("A Part 2 is Completed!");
    }
    AbstractProduct* GetProduct() // 返回构建的产品A
    {
    return m_pProduct;
    }
    };

    // Builder B
    class BuilderB: public AbstractBuilder //构建产品B内部部分
    {
    private:
    AbstractProduct *m_pProduct; // 被构建的抽象产品指针
    public:
    BuilderB()
    {
    m_pProduct = new ProductB(); //构建产品B
    }
    void BuilderPart1()
    {
    m_pProduct->AddPart("B Part 1 is Completed!");
    }
    void BuilderPart2()
    {
    m_pProduct->AddPart("B Part 2 is Completed!");
    }
    AbstractProduct* GetProduct() // 返回构建的产品B
    {
    return m_pProduct;
    }
    };
  5. 定义引导者Director类,提供一个创建最终产品的接口,该接口使用Builder的方法来组装创建产品:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Director
    {
    private:
    AbstractBuilder *m_pBuilder;
    public:
    Director(AbstractBuilder *pbuilder): m_pBuilder(pbuilder) {};
    void CreateProduct() // 组装整个产品
    {
    m_pBuilder->BuilderPart1();
    m_pBuilder->BuilderPart2();
    }
    };
  6. 测试建造者模式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    void BuilderTest()
    {
    AbstractBuilder *pAB = new BuilderA(); // 构建产品A
    Director *pD = new Director(pAB);
    pD->CreateProduct(); // 引导者负责通过 Builder 组装产品
    AbstractProduct *pAP = pAB->GetProduct(); // 建造者负责 具体的Builder 组装产品,并提供获取产品接口
    pAP->ShowProduct();

    AbstractBuilder *pAB2 = new BuilderB(); // 构建产品B
    Director *pD2 = new Director(pAB2);
    pD2->CreateProduct(); // 引导者负责通过 Builder 组装产品
    AbstractProduct *pAP2 = pAB2->GetProduct(); // 建造者负责 具体的Builder 组装产品,并提供获取产品接口
    pAP2->ShowProduct();

    delete pAB; pAB = NULL;
    delete pD; pD = NULL;
    delete pAP; pAP = NULL;

    delete pAB2; pAB2 = NULL;
    delete pD2; pD2 = NULL;
    delete pAP2; pAP2 = NULL;
    }

运行结果:

I am Product A!
A Part 1 is Completed!
A Part 2 is Completed!
I am Product B!
B Part 1 is Completed!
B Part 2 is Completed!

使用场景

  • 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性
  • 需要生成的产品对象的属性相互依赖,需要指定其生成顺序
  • 对象的创建过程独立于创建该对象的类,在Builder模式中通过引入Director类,将创建的过程封装在Director类中而非Builder或Client类中
  • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品

优缺点

  • 优点:
    • 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
    • 当需要创建复杂对象的过程中,复杂对象没有多少共同的特点,很难抽象出来时,
      而复杂对象的组装又有一定的相似点时,建造者模式就可以发挥出作用
    • 由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”
    • 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程
  • 缺点:
    • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制
    • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本

与工厂模式的区别


都属于创建型的设计模式,所以二者之间是有公共点,但是建造者模式注重于对象组合,即不同的小对象组成一个整体的复杂大对象;而抽象工厂模式针对于接口编程,只是对外提供创建对象的工厂接口,不负责对象之后的处理

建造者模式具体实例


构建一个人对象,包括胖和瘦两种类型,每个人都包含头、身体、手和脚四部分

代码实现

  1. 抽象的ManBuilder类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 抽象的人建造者类
    class ManBuilder
    {
    public:
    // 建造人的不同部位
    virtual void BuilderHead() = 0;
    virtual void BuilderBody() = 0;
    virtual void BuilderHand() = 0;
    virtual void BuilderLeg() = 0;
    };
  2. 具体的两个建造者ThinBuilder和FatBuilder分别构建胖子和瘦子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    // 具体的瘦人建造者
    class ThinBuilder: public ManBuilder
    {
    public:
    void BuilderHead()
    {
    cout << "Thin Builder Head" << endl;
    }
    void BuilderBody()
    {
    cout << "Thin Builder Body" << endl;
    }
    void BuilderHand()
    {
    cout << "Thin Builder Hand" << endl;
    }
    void BuilderLeg()
    {
    cout << "Thin Builder Leg" << endl;
    }
    };

    // 具体的胖人建造者
    class FatBuilder: public ManBuilder
    {
    public:
    void BuilderHead()
    {
    cout << "Fat Builder Head" << endl;
    }
    void BuilderBody()
    {
    cout << "Fat Builder Body" << endl;
    }
    void BuilderHand()
    {
    cout << "Fat Builder Hand" << endl;
    }
    void BuilderLeg()
    {
    cout << "Fat Builder Leg" << endl;
    }
    };
  3. 最终创建人对象的ManDirector引导者类调用ManDirector的方法来组装和创建具体类型的人:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class ManDirector
    {
    private:
    ManBuilder *m_pBuilder; // 抽象的ManBuilder
    public:
    ManDirector(ManBuilder *pBuilder): m_pBuilder(pBuilder) {};
    void CreateMan() // 使用ManBuilder的方法构建最终的Man
    {
    m_pBuilder->BuilderHead();
    m_pBuilder->BuilderBody();
    m_pBuilder->BuilderHand();
    m_pBuilder->BuilderLeg();
    }
    };
  4. 客户端测试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void ManBuilderTest()
    {
    ManBuilder *pMB = new ThinBuilder();
    ManDirector MD(pMB);
    MD.CreateMan();

    ManBuilder *pMB2 = new FatBuilder();
    ManDirector MD2(pMB2);
    MD2.CreateMan();

    delete pMB; pMB = NULL;
    delete pMB2; pMB2 = NULL;
    }

运行结果:

Thin Builder Head
Thin Builder Body
Thin Builder Hand
Thin Builder Leg
Fat Builder Head
Fat Builder Body
Fat Builder Hand
Fat Builder Leg