【设计模式】 模式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、总结

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

● 意图不同
在工厂方法模式里,我们关注的是一个产品整体,如超人整体,无须关心产品的各部分是如何创建出来的;但在建造者模式中,一个具体产品的产生是依赖各个部件的产生以及装配顺序,它关注的是“由零件一步一步地组装出产品对象”。简单地说,工厂模式是一个对象创建的粗线条应用,建造者模式则是通过细线条勾勒出一个复杂对象,关注的是产品组成部分的创建过程。
● 产品的复杂度不同
工厂方法模式创建的产品一般都是单一性质产品,如成年超人,都是一个模样,而建造者模式创建的则是一个复合产品,它由各个部件复合而成,部件不同产品对象当然不同。这不是说工厂方法模式创建的对象简单,而是指它们的粒度大小不同。一般来说,工厂方法模式的对象粒度比较粗,建造者模式的产品对象粒度比较细。
两者的区别有了,那在具体的应用中,我们该如何选择呢?是用工厂方法模式来创建对象,还是用建造者模式来创建对象,这完全取决于我们在做系统设计时的意图,如果需要详细关注一个产品部件的生产、安装步骤,则选择建造者,否则选择工厂方法模式。

时间: 2024-08-11 01:22:28

【设计模式】 模式PK:工厂模式VS建造者模式的相关文章

java/android 设计模式学习笔记(10)---建造者模式

这篇博客我们来介绍一下建造者模式(Builder Pattern),建造者模式又被称为生成器模式,是创造性模式之一,与工厂方法模式和抽象工厂模式不同,后两者的目的是为了实现多态性,而 Builder 模式的目的则是为了将对象的构建与展示分离.Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程.一个复杂的对象有大量的组成部分,比如汽车它有车轮.方向盘.发动机.以及各种各样的小零件,要将这些部件装配成一辆汽车,这个装配过

Java设计模式学习笔记,三:建造者模式

建造者模式:实现了构建和装配的解耦,即对象的各个子组件单独构建,再进行装配,从而建造完整对象. 该模式适用于构建较为复杂的对象(多个子组件). 不同的构建者,使用相同的装配者,可以建造不同的对象实例.相同的构建者,不同的装配顺序,也可能建造出不同的对象实例. 举例: 汽车对象,子组件包括引擎.轮子和车体. Audi汽车构建者,负责制造Audi牌各个子组件.BMW汽车构建者,负责制造BMW牌各个子组件.然后将子组件统一送至汽车装配者的生产线中进行组装,最后会建造出Audi牌汽车和BMW汽车. 以下

设计模式(十六):建造者模式

一.概述 建造者模式很容易让人想到建房子,不管建刚需房.改善房还是别墅,它们都离不开地基.柱子.层面和墙体这些组成部分,建筑工人就是把这些组成部分一个个建起来,最后连成一体建出一栋栋楼房. 来看看建造者模式的定义,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.建房子的过程都是相似的,但可以建出形形色色的房子. 二.结构类图 三.应用实例 我们用制造自行车为例子讲解建造者模式,自行车由车架.轮胎.脚踏等部件组成,如下图所示.自行车制造公司就是把这些零部件组装起来. 自行

设计模式在游戏中的应用--建造者模式(九)

建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.建造者模式是一种对象创建型模式.通过这个定义,我们可以得出建造者是一种创建型模式,也就是说建造者模式的输出是一个对象,也就是UML类图中的product. 我们先看看建造者模式的UML类图: UML类图中我们可以看出,建造者模式使用了聚合.继承和依赖三种关系.第一个疑问就是为什么要使用聚合,如果我们不使用聚合的话,我们始终得到的都是稳定的构建过程,例如我们游戏中每个NPC都有2

《大话设计模式》学习笔记9:建造者模式

建造小人示例: 1.Builder: public abstract class PersonBuilder { public abstract void BuildHead(); public abstract void BuildBody(); public abstract void BuildArm(); public abstract void BuildLeg(); } 2.ConcreteBuilder: public class ThinPersonBuilder:PersonB

大话设计模式C++实现-第13章-建造者模式

一.UML图 二.概念 建造者模式(Builder):将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示. 三.说明 角色: (1)Builder:是为创建一个Product对象的各个部件指定的抽象接口. (2)ConcreteBuilder:是具体创建者,实现Builder接口,构造和装配各个部件. (3)Product:具体的产品角色. (4)Director:指挥者,他是构建一个使用Builder接口的对象. Q:什么时候使用建造者模式? A:它主要是用于创建一些复杂

设计模式(五)Builder Pattern建造者模式

在我们日常生活中,如构建一个飞船,一个手机,一栋建筑,都会有非常复杂的组装,这时候应该用到建造者模式 以建造一个飞船为例 案例:造小页飞船 1.飞船各部分元件 package com.littlepage.BuilderPattern; public interface AirShipBuilder { Engine builderEngine(); OrbitalModule builderOrbitalModule(); Escape builderEscape(); } 2.飞船实体用来组

【java设计模式】之 工厂(Factory)模式

1.工厂模式的定义 工厂模式使用的频率非常高,我们在开发中总能见到它们的身影.其定义为:Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.即定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类

简单工厂模式PK工厂方法模式

在前一章节我们讲到了简单工厂模式,它的已入确实为我们的代码增添了灵活性.可继续.那么为什么在还有工厂方法模式呢? 什么是工厂方法模式呢?定义一个创建对象的接口,让子类决定实例化哪个类.工厂方法使实例化延迟到子类中.简单点说就是为每一个具体类创建一个工厂类(此类是继承抽象工厂类).那么我们在客户端时候,直接用对应的工厂类创建实例. 用简单工厂模式,我们如果需要添加行的计算方法(以运算扩充为例),那需要重新写一个继承运算类的具体类.我们而且需要修改工厂类中的判断逻辑.这样做的话就会和我们先前将的一个

【图解】抽象工厂模式PK建造者模式

抽象工厂模式: 如果换成建造者模式,建造者会先组装车的各个零配件,然后在生产成一部车. [图解]抽象工厂模式PK建造者模式