• 设计模式---对象创建模式之构建器模式(Builder)


    一:概念

    Builder模式也叫建造者模式或者生成器模式,是由GoF提出的23种设计模式中的一种。Builder模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。
    对象的创建:Builder模式是为对象的创建而设计的模式
    
    创建的是一个复合对象:被创建的对象为一个具有复合属性的复合对象
    
    关注对象创建的各部分的创建过程:不同的工厂(这里指builder生成器)对产品属性有不同的创建方法。

    二:动机

    在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将他们组合在一起的算法却相对稳定
    如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变。

    三:代码解析(建造房子)

    class House{
        //....
    
         House(){ // 错误示例,不能这样写
    
            this->BuildPart1(); // 构造函数中是静态绑定,此时调用纯虚函数会报错,不会去调用子类
    
            for (int i = 0; i < 4; i++){
                this->BuildPart2();
            }
    
            bool flag = pHouseBuilder->BuildPart3();
    
            if (flag){
                this->BuildPart4();
            }
    
            this->BuildPart5();
        }
    
        void Init(){ // 流程相对固定
    
            this->BuildPart1(); // 构造第一部分
    
            for (int i = 0; i < 4; i++){
                this->BuildPart2();
            }
    
            bool flag = pHouseBuilder->BuildPart3();
    
            if (flag){
                this->BuildPart4();
            }
    
            this->BuildPart5();        
        }
        virtual ~HouseBuilder(){}
    protected:    
        virtual void BuildPart1() = 0;
        virtual void BuildPart2() = 0;
        virtual void BuildPart3() = 0;
        virtual void BuildPart4() = 0;
        virtual void BuildPart5() = 0;
    };
    C++构造函数中,是不会去调用子类的虚函数。
    子类构造函数会先去调用父类构造函数,如果子类调用父类构造,父类构造中去寻找子类虚函数,会报错,因为子类构造函数还没有完成,子类虚函数先被调用,这违背对象的构造原理
    class StoneHouse: public House{  //各种房子
    
    protected:
    
        virtual void BuildPart1(){
            //pHouse->Part1 = ...;
        }
        virtual void BuildPart2(){
    
        }
        virtual void BuildPart3(){
    
        }
        virtual void BuildPart4(){
    
        }
        virtual void BuildPart5(){
    
        }
    };

    四:模式定义

      将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。
    
                                                  --《设计模式》Gof   
    Init就是同一个构建过程,而每一个对象我们只需要实现其构建步骤就可以创建不同的表示
    int main()
    {
        House* pHouse = new StoneHouse();
        pHouse->Init();
    }

    五:进一步优化(对象过于复杂,除了上面步骤还有其他方法和属性)

    class House{ // 表示  抽象基类
        //.... house 与 HouseBuilder 相分离
    };
    
    class HouseBuilder {  // 构建  抽象基类
    public:
        House* GetResult(){
            return pHouse;
        }
        virtual ~HouseBuilder(){}
    protected:
        
        House* pHouse;
        virtual void BuildPart1()=0;
        virtual void BuildPart2()=0;
        virtual void BuildPart3()=0;
        virtual void BuildPart4()=0;
        virtual void BuildPart5()=0;
        
    };
    
    class StoneHouse: public House{
        
    };
    
    class StoneHouseBuilder: public HouseBuilder{
    protected:
        
        virtual void BuildPart1(){
            //pHouse->Part1 = ...;
        }
        virtual void BuildPart2(){
            
        }
        virtual void BuildPart3(){
            
        }
        virtual void BuildPart4(){
            
        }
        virtual void BuildPart5(){
            
        }
        
    };
    
    // 稳定
    class HouseDirector{  // 同样的构建过程
        
    public:
        HouseBuilder* pHouseBuilder;
        
        HouseDirector(HouseBuilder* pHouseBuilder){
            this->pHouseBuilder=pHouseBuilder;
        }
        
        House* Construct(){
            
            pHouseBuilder->BuildPart1();
            
            for (int i = 0; i < 4; i++){
                pHouseBuilder->BuildPart2();
            }
            
            bool flag=pHouseBuilder->BuildPart3();
            
            if(flag){
                pHouseBuilder->BuildPart4();
            }
            
            pHouseBuilder->BuildPart5();
            
            return pHouseBuilder->GetResult();
        }
    };
    HouseBuilder管构建,House将其分离出去,而创建步骤又是稳定的,我们再一步进行拆分为HouseDiretor,避免类的肥大

    六:类图(结构)

    类复杂就拆分,类简单就合并

    七:要点总结

    (一)Builder模式主要用于“分步骤构建一个复杂对象”。在这其中“分步骤”是一个稳定算法,而复杂对象的各个部分则经常变化

    (二)变化的点在哪里,封装哪里——Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。

    (三)在Builder模式中,要注意不同语言中构造器内调用虚函数的差别(C++ vs. C#)。

    八:构建器和工厂模式区别

    (一)Factory模式中:

    1.有一个抽象的工厂。
    2.实现一个具体的工厂---汽车工厂。
    3.工厂生产汽车A,得到汽车产品A。
    4.工厂生产汽车B,得到汽车产品B。
    这样做,实现了购买者和生产线的隔离。

    (二)Builder模式:

    1.离合器工厂生产离合器产品,得到汽车部件A。
    2.轮胎工厂生产轮子产品,得到汽车部件B。
    3.车身工厂生产车身产品,得到汽车部件C。
    4.将这些部件放到一起,形成刚好能够组装成一辆汽车的整体。
    5.将这个整体送到汽车组装工厂,得到一个汽车产品。
    或者更抽象一点理解:
    1.将汽车的每一个零件都送到汽车组装工厂。
    2.在工厂里,组装离合器,得到汽车部件A。
    3.在工厂里,组装轮胎,得到汽车部件B。
    4.在工厂里,组装车身,得到汽车部件C。
    5.在工厂里,组装每个部件,得到一个汽车产品。
    这样做,目的是为了实现复杂对象生产线和其部件的解耦。

    (三)二者不同在于:

    Factory模式不考虑对象的组装过程,而直接生成一个我想要的对象。
    Builder模式先一个个的创建对象的每一个部件,再统一组装成一个对象。
    Factory模式所解决的问题是,工厂生产产品。而Builder模式所解决的问题是工厂控制产品生成器组装各个部件的过程,然后从产品生成器中得到产品。

    九:案例实现(建房子)

    (一)实现抽象类Director(工程师),House(房子),HouseBuilder(工程队)

    class House
    {
    private:
        string m_floor;
        string m_wall;
        string m_door;
    public:
        void setFloor(string floor)
        {
            this->m_floor = floor;
        }
    
        void setWall(string wall)
        {
            this->m_wall = wall;
        }
    
        void setDoor(string door)
        {
            this->m_door = door;
        }
    
        void getFloor()
        {
            cout << "install " << this->m_floor << endl;
        }
    
        void getWall()
        {
            cout << "install " << this->m_wall << endl;
        }
    
        void getDoor()
        {
            cout << "install " << this->m_door << endl;
        }
    };
    
    class HouseBuilder
    {
    protected:
        House* pHouse;
    
    public:
        virtual void BuildFloor() = 0;
        virtual void BuildWall() = 0;
        virtual void BuildDoor() = 0;
    
        House* GetResult()
        {
            return pHouse;
        }
    };
    
    class HouseDirector
    {
    public:
        HouseBuilder* pHouseBuilder;
    
        HouseDirector(HouseBuilder* pHouseBuilder)
        {
            this->pHouseBuilder = pHouseBuilder;
        }
    
        House* Construct()
        {
            pHouseBuilder->BuildWall();
            pHouseBuilder->BuildFloor();
            pHouseBuilder->BuildDoor();
            return pHouseBuilder->GetResult();
        }
    };

    (二)实现具体房子类和建造类

    class StoneHouseBuilder :public HouseBuilder
    {
    public:
        StoneHouseBuilder()
        {
            pHouse = new House();
        }
    
        virtual void BuildFloor()
        {
            pHouse->setFloor("stone floor");
        }
    
        virtual void BuildWall()
        {
            pHouse->setWall("stone wall");
        }
    
        virtual void BuildDoor()
        {
            pHouse->setDoor("stone door");
        }
    };
    
    class FlatHouseBuilder :public HouseBuilder
    {
    public:
        FlatHouseBuilder()
        {
            pHouse = new House();
        }
    
        virtual void BuildFloor()
        {
            pHouse->setFloor("flat floor");
        }
    
        virtual void BuildWall()
        {
            pHouse->setFloor("flat wall");
        }
    
        virtual void BuildDoor()
        {
            pHouse->setFloor("flat door");
        }
    };

    (三)工程师步骤指挥,按步骤创建房屋

    void main()
    {
        HouseBuilder* HB = new StoneHouseBuilder();
        HouseDirector* HD = new HouseDirector(HB);
        House* H = HD->Construct();
    
        H->getWall();
        H->getFloor();
        H->getDoor();
    
        delete H;
        delete HB;
        delete HD;
    
        system("pause");
        return;
    }

  • 相关阅读:
    mybatis中的#和$的区别
    Java 导出 CSV
    java生成UUID
    Java并发编程的艺术(七)——Executors
    Java并发编程的艺术(六)——线程间的通信
    Java并发编程的艺术(五)——中断
    Java并发编程的艺术(四)——线程的状态
    Java并发编程的艺术(三)——volatile
    Java并发编程的艺术(二)——重排序
    Java并发编程的艺术(一)——并发编程需要注意的问题
  • 原文地址:https://www.cnblogs.com/ssyfj/p/9538292.html
Copyright © 2020-2023  润新知