1、概述

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

2、工厂方法建造超人

2.1 类图

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

2.2 代码实现

2.2.1 抽象超人

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

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

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 ;
}

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() = ; 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 ;
}

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

4、总结

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

  ● 意图不同

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

  ● 产品的复杂度不同

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

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

  1. 设计模式实战系列之@Builder和建造者模式

    前言 备受争议的Lombok,有的人喜欢它让代码更整洁,有的人不喜欢它,巴拉巴拉一堆原因.在我看来Lombok唯一的缺点可能就是需要安装插件了,但是对于业务开发的项目来说,它的优点远远超过缺点. 我们 ...

  2. [Python设计模式] 第13章 造小人——建造者模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟一个画小人的过程,要求小人要有头,身子,左手,右手,左脚,右脚 ...

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

    在我们日常生活中,如构建一个飞船,一个手机,一栋建筑,都会有非常复杂的组装,这时候应该用到建造者模式 以建造一个飞船为例 案例:造小页飞船 1.飞船各部分元件 package com.littlepa ...

  4. 《大话设计模式》ruby版代码:建造者模式

    需求: 画一个小人,有头,有身体,两手两脚即可. 初始代码: # -*- encoding: utf-8 -*- #小人一 puts '这是第一个小人' puts '小人一:头' puts '小人一: ...

  5. 002-创建型-04-建造者模式(Builder)、JDK1.7源码中的建造者模式、Spring中的建造者模式

    一.概述 建造者模式的定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象 ...

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

    1.工厂模式的定义 工厂模式使用的频率非常高,我们在开发中总能见到它们的身影.其定义为:Define an interface for creating an object, but let subc ...

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

    一.引言 在软件系统中,有时需要创建一个复杂对象,并且这个复杂对象由其各部分子对象通过一定的步骤组合而成.例如一个采购系统中,如果需要采购员去采购一批电脑时,在这个实际需求中,电脑就是一个复杂的对象, ...

  8. C#设计模式(5)——建造者模式(Builder Pattern)

    一.引言 在软件系统中,有时需要创建一个复杂对象,并且这个复杂对象由其各部分子对象通过一定的步骤组合而成.例如一个采购系统中,如果需要采购员去采购一批电脑时,在这个实际需求中,电脑就是一个复杂的对象, ...

  9. .NET设计模式(4):建造者模式(Builder Pattern)(转)

    概述 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成:由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定. ...

  10. C++设计模式——建造者模式

    建造者模式 在GOF的<设计模式 可复用面向对象软件的基础>中是这样说的:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 这句话,似懂非懂的.一个复杂对象的创建 ...

随机推荐

  1. Unity3D学习笔记(十九):UGUI、Image、Text、Button

    UGUI:Unity官方最新,与NGUI同源 UI:User Interface(用户的操作界面),图片+文字 UGUI的组件: 1.创建UGUI组件时,会默认创建Canvas(画布)和EventSy ...

  2. Python day9函数部分

    函数的学习:函数对于一门编程语言来说挺重要的,尤其是c语言,是完全使用函数来编写的 1.函数的定义:逻辑结构化和过程化的一种编程方法 def squre(x): "求一个数的平方 retur ...

  3. eclipse开发go语言入门案例

    1.配置eclipse下配置GO语言的插件 点击eclipse的“Help”菜单,找到“Install New Software…”菜单项.如下图: 点击“Install New Software…” ...

  4. 让flask在出现语法错误时仍然自动重启

    1问题描述: flask自带的reload只能在语法没毛病的情况下auto_relaod,但是如果有语法错误,进程就会报错退出. 这时修改完语法错误,还得在控制台按“↑”和“enter”重新执行一次p ...

  5. NHibernate 映射关系

    基本映射关系如下: NHibernate类型 .NET类型 Database类型 备注 AnsiChar System.Char DbType.AnsiStringFixedLength - 1 ch ...

  6. 新概念 Lesson 4 Are you a teacher

    打招呼用语: Good morning, Good afternoon,Good evening Nice to meet you. How do you do? She is French. 她是法 ...

  7. Confluence 6 自动添加用户到用户组

    默认组成员(Default Group Memberships) 选项在 Confluence 3.5 及后续版本和 JIRA 4.3.3 及后续版本中可用.这字段将会在你选择 'Read Only, ...

  8. 移动端web开发技巧(转)

    原文链接:http://liujinkai.com/2015/06/06/mobile-web-skill/ 移动端web开发技巧 这是一个最好的时代,因为我们站在潮流中:但也是一个最坏的时代,因为我 ...

  9. 『科学计算_理论』SVD奇异值分解

    转载请声明出处 SVD奇异值分解概述 SVD不仅是一个数学问题,在工程应用中的很多地方都有它的身影,比如前面讲的PCA,掌握了SVD原理后再去看PCA那是相当简单的,在推荐系统方面,SVD更是名声大噪 ...

  10. YOLO v2 损失函数源码分析

    损失函数的定义是在region_layer.c文件中,关于region层使用的参数在cfg文件的最后一个section中定义. 首先来看一看region_layer 都定义了那些属性值: layer ...