• 【设计模式】 模式PK:工厂模式VS建造者模式


    1、概述

      工厂方法模式注重的是整体对象的创建方法,而建造者模式注重的是部件构建的过程,旨在通过一步一步地精确构造创建出一个复杂的对象。我们举个简单例子来说明两者的差异,如要制造一个超人,如果使用工厂方法模式,直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人;而如果使用建造者模式,则需要组装手、头、脚、躯干等部分,然后再把内裤外穿,才能创造一个超人。

    2、工厂方法建造超人

    2.1 类图

      首先我们按照工厂方法创造超人,我们来看类图。类图中我们按照年龄段把超人分为两种类型:成年超人(如克拉克、超能先生)和未成年超人(如Dash、Jack)。这是一个非常正宗的工厂方法模式,定义一个产品的接口,然后再定义两个实现,通过超人制造工厂制造超人。

    2.2 代码实现

    2.2.1 抽象超人

      想想看我们对超人最大印象是什么?当然是他的超能力,我们以specialTalent(特殊天赋)方法来代表,先看抽象产品类。

    class CISuperMan
    {
    public:
        CISuperMan(){};
        ~CISuperMan(){};
        virtual void mvSpecialTalent() = 0;
    };

    2.2.2 成年超人

      产品的接口定义好了,我们再来看具体的产品。先看成年超人,很简单。

    class CAdultSuperMan : public CISuperMan
    {
    public:
        CAdultSuperMan(){};
        ~CAdultSuperMan(){};
        void mvSpecialTalent()
        {
            cout << "超人力大无穷" << endl;
        }
    };

    2.2.3 未成年超人

    class ChildSuperMan : public CISuperMan
    {
    public:
        ChildSuperMan(){};
        ~ChildSuperMan(){};
        void mvSpecialTalent()
        {
            cout << "小超人的能力是刀枪不入、 快速运动" << endl;
        }
    };

    2.2.4 工厂

      产品都具备,那我们编写一个工厂类,其意图就是生产超人,具体是成年超人还是未成年超人,则由客户端决定。

    class CSuperManFactory
    {
    public:
        CSuperManFactory(){};
        ~CSuperManFactory(){};
        CISuperMan *mopCreateSuperMan(string sType)
        {
            if ("adult" == sType)
            {
                return new CAdultSuperMan;
            }
            else if ("child" == sType)
            {
                return new CChildSuperMan;
            }
            else
            {
                return NULL;
            }
        }
    };

    2.2.5 调用

      产品有了,工厂类也有了,剩下的工作就是开始生产超人。

    int main()
    {
        CSuperManFactory o_factory;
        CISuperMan *op_super = o_factory.mopCreateSuperMan("adult");
        op_super->mvSpecialTalent();
    
        return 0;
    }

    2.3 总结

      建立了一个超人生产工厂,年复一年地生产超人,对于具体生产出的产品,不管是成年超人还是未成年超人,都是一个模样:深蓝色紧身衣、胸前S标记、内裤外穿,没有特殊的地方。但是我们的目的达到了——生产出超人,这就是我们的意图。具体怎么生产、怎么组装,这不是工厂方法模式要考虑的,也就是说,工厂模式关注的是一个产品整体,生产出的产品应该具有相似的功能和架构。

      注意:通过工厂方法模式生产出对象,然后由客户端进行对象的其他操作,但是并不代表所有生产出的对象都必须具有相同的状态和行为,它是由产品所决定。

    3、建造者模式建造超人

    3.1 类图

      我们在抽象建造者上使用了模板方法模式,每一个建造者都必须返回一个产品,但是产品是如何制造的,则由各个建造者自己负责。

    3.2 代码

    3.2.1 产品类

      超人这个产品是由三部分组成:躯体、特殊技能、身份标记,这就类似于电子产品,首先生产出一个固件,然后再安装一个灵魂(软件驱动),最后再打上产品标签。一个崭新的产品就诞生。我们的超人也是这样生产的,先生产一个普通的躯体,然后注入特殊技能,最后打上S标签,一个超人生产完毕。

    class CSuperMan
    {
    public:
        CSuperMan(){};
        ~CSuperMan(){};
    
        string msGetBody() { return msBody; };
        void mvSetBody(const string &sBody) { msBody = sBody; };
    
        string msGetSpecialTalent() { return msSpecialTalent; };
        void mvSetSpecialTalent(const string &sSpecialTalent) { msSpecialTalent = sSpecialTalent; };
    
        string msGetSpecialSymbol() { return msSpecialSymbol; };
        void mvSetSpecialSymbol(const string &sSpecialSymbol) { msSpecialSymbol = sSpecialSymbol; };
    
    private:
        string msBody;             //超人的躯体
        string msSpecialTalent;    //超人的特殊技能
        string msSpecialSymbol;    //超人的标志
    };

    3.2.2 抽象建造者

      一个典型的模板方法模式,超人的各个部件(躯体、灵魂、标志)都准备好了,具体怎么组装则是由实现类来决定。

    class CBuilder
    {
    protected:
        CBuilder() { mopSuperMan = new CSuperMan; };
        ~CBuilder();
    
        void mvSetBody(const string &sBody) { this->mopSuperMan->mvSetBody(sBody); };
        void mvSetSpecialTalent(const string &sSpecialTalent) { this->mopSuperMan->mvSetSpecialTalent(sSpecialTalent); };
        void mvSetSpecialSymbol(const string &sSpecialSymbol) { this->mopSuperMan->mvSetSpecialSymbol(sSpecialSymbol); };
    
    public:
        virtual CSuperMan  *mopGetSuperMan() = 0;
    
    protected:
        CSuperMan *mopSuperMan;
    };

    3.2.3 成年超人

      设计模式只是提供了一个解决问题的意图:复杂对象的构建与它的表示分离,而没有具体定出一个设计模式必须是这样的实现,必须是这样的代码,灵活运用模式才是其根本,我们通过模版方法加上建造者模式来建造超人。

    class CAdultSuperManBuilder : public CBuilder
    {
    public:
        CAdultSuperManBuilder(){};
        ~CAdultSuperManBuilder(){};
    
        CSuperMan  *mopGetSuperMan()
        {
            mvSetBody("强壮的躯体");
            mvSetSpecialTalent("会飞行");
            mvSetSpecialSymbol("胸前带S标记");
    
            return mopSuperMan;
        }
    };

    3.2.4 未成年超人

    class CChildSuperManBuilder : public CBuilder
    {
    public:
        CChildSuperManBuilder(){};
        ~CChildSuperManBuilder(){};
    
        CSuperMan  *mopGetSuperMan()
        {
            mvSetBody("强壮的躯体");
            mvSetSpecialTalent("刀枪不入");
            mvSetSpecialSymbol("胸前带S标记");
    
            return mopSuperMan;
        }
    };

      大家注意看我们这两个具体的建造者,它们都关注了产品的各个部分,在某些应用场景下甚至会关心产品的构建顺序,即使是相同的部件,装配顺序不同,产生的结果也不同,这也正是建造者模式的意图:通过不同的部件、不同装配产生不同的复杂对象。

    3.2.5 导演类

      导演类很简单就不多说了。

    class CDirector {
    public:
        CDirector(){};
        ~CDirector(){};
        //两个建造者的应用
        CBuilder *mopAdultBuilder = new CAdultSuperManBuilder();
        //未成年超人的建造者
        CBuilder *CChildBuilder = new CChildSuperManBuilder();
        //建造一个成年、 会飞行的超人
        CSuperMan *mopGetAdultSuperMan(){ return mopAdultBuilder->mopGetSuperMan();     } 
        // 建造一个未成年、 刀枪不入的超人
        CSuperMan *mopGetChildSuperMan(){ return CChildBuilder->mopGetSuperMan(); }
    };

    3.2.6 场景调用

    int main()
    {
        CDirector o_director;
    
        //建造一个成年超人
        CSuperMan *op_adult = o_director.mopGetAdultSuperMan();
    
        // 展示超人信息
        cout << op_adult->msGetSpecialTalent().c_str() << endl;
    
        return 0;
    }

      这个场景类的写法与工厂方法模式是相同的,但是你可以看到,在建立超人的过程中,建造者必须关注超人的各个部件,而工厂方法模式则只关注超人的整体,这就是两者的区别。

    4、总结

      工厂方法模式和建造者模式都属于对象创建类模式,都用来创建类的对象。但它们之间的区别还是比较明显的。

      ● 意图不同

      在工厂方法模式里,我们关注的是一个产品整体,如超人整体,无须关心产品的各部分是如何创建出来的;但在建造者模式中,一个具体产品的产生是依赖各个部件的产生以及装配顺序,它关注的是“由零件一步一步地组装出产品对象”。简单地说,工厂模式是一个对象创建的粗线条应用,建造者模式则是通过细线条勾勒出一个复杂对象,关注的是产品组成部分的创建过程。

      ● 产品的复杂度不同

      工厂方法模式创建的产品一般都是单一性质产品,如成年超人,都是一个模样,而建造者模式创建的则是一个复合产品,它由各个部件复合而成,部件不同产品对象当然不同。这不是说工厂方法模式创建的对象简单,而是指它们的粒度大小不同。一般来说,工厂方法模式的对象粒度比较粗,建造者模式的产品对象粒度比较细。
      两者的区别有了,那在具体的应用中,我们该如何选择呢?是用工厂方法模式来创建对象,还是用建造者模式来创建对象,这完全取决于我们在做系统设计时的意图,如果需要详细关注一个产品部件的生产、安装步骤,则选择建造者,否则选择工厂方法模式。

  • 相关阅读:
    中阶 d04.1 xml解析
    中阶 d04 xml 概念及使用
    中阶 d03.5 (正篇)完整的Dao 操作数据库
    中阶d03.4 JDBC_DAO
    中阶d03.3 JDBC_CURD_Util --- 使用 junit执行单元测试(增删改查)
    单元测试 junit
    idle中上传jar包并使用的方法
    intelij idea 和 eclipse 使用上的区别
    中阶d03.2 JDBC联合properties使用,通过读取本地配置文件为代码传递参数
    swift init 初始化
  • 原文地址:https://www.cnblogs.com/ChinaHook/p/7471470.html
Copyright © 2020-2023  润新知