写在前面

为方便读者,本文已添加至索引

作为一个新入职的魔导士呢,哦不,是程序员,我以为并没有太多机会去设计项目的软件架构。但是,工作一段时间之后,自己渐渐意识到,哪怕是自己要去做的小feature,也是需要去好好设计。我就应该做好它的架构师。看过一些牛人的文章后,总算意识到自己应该好好学习下设计模式。尽管并不是为了把设计模式作为教条式的方案套用到现实的工作中去,起码我也要做到心中有佛吧,...是心中有数,再在日后工作中积累经验,达到融汇贯通的境地。设计模式是前人总结出的相当重要的经验,也是针对特定问题的简洁而优雅的解决方案。我想,它们不仅在面向对象(OO)设计中极具参考价值,更能推广到日常生活方方面面。因此,我还是好好地学习下设计模式,在此记录自己的学习笔记。废话不多说,开始第一篇:Builder模式。

要点梳理

  • 目的分类

    • 对象创建型模式
  • 范围准则
    • 对象
  • 主要功能
    • 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  • 适用情况
    • 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时;
    • 当构造过程必须允许被构造的对象有不同的表示时;
  • 参与部分
    • Builder:为创建一个Product对象的各个部件指定抽象接口
    • ConcreteBuilder:具体实现Builder的接口以构造和装配该产品的各个部件的生成器;定义并明确它所创建的表示;提供一个返回检索其Product的接口
    • Director:使用Builder接口的对象,称为导向器
    • Product:它表示被构造的复杂对象;包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
  • 协作过程
    • 我们首先创建Director对象,并用它所想要的Builder对象进行配置
    • 一旦Product部件被生成,导向器就会通知生成器
    • 生成器处理导向器的请求,并将部件添加到该Product中
    • 我们可以通过生成器检索最后成品

示例分析 - 世界创造器

总觉得书上讲的例子会否太过严肃,我在这里还是祭出时の魔导士(Mage)的大杀器,神奇的“世界创造器”--WorldCreator吧!平行世界的概念想必大家都懂,现在让我们来看看,Mage如果要用咒语createWorld来生成一个平行世界,让可爱的白雪公主和7个霍比特人幸福快乐地生活,我们从哪开始呢?(貌似混进了奇怪的事情。)那就让我们从WorldCreator类开始吧,它定义了以下接口来创造世界:

 class WorldCreator {
public:
virtual void createWorld() {}
virtual void createMountains(int m) {}
virtual void createPlants(int p) {}
virtual void createBuildings(int b) {}
virtual World* getWorld() { return ; }
protected:
WorldCreator();
};

首先建立一个平行世界,然后造山,造树,造房子,嗯......咦,怎么都是virtual?没错!WorldCreator就是前文所提的Builder,它自己并不实际用来创造世界,而是由它的子类来完成;它的主要目的仅仅是为创造世界提供接口,并且,这些接口缺省操作虽然是空,什么也不做,但也不定义成纯虚函数。因为这样便于子类只重定义它们所感兴趣的那些方法。比方说,我突然又想创造一个许多元素生物存在的世界,那里压根没有人工建筑Buildings,那么我就不用重写createBuildings方法了。后面会继续讲到。

有了WorldCreator,我们来看看Mage的createWorld咒语(圈内术语应该叫Mage类的createWorld成员函数)到底是什么样的吧:

 World* Mage::createWorld(WorldCreator& builder) {
builder.createWorld();
builder.createMountains();
builder.createPlants();
builder.createBuildings(); return builder.getWorld();
}

像其他创建型模式一样,Builder模式封装了对象是如何被创建的,在这个例子中是通过WorldCreator所定义的接口来封装的。这就意味着我们的Mage可以重用WorldCreator来创造不同种类的世界,比方说,前面提到的没有人工建筑的世界:

 World* Mage::createEarthElementalWorld(WorldCreator& builder) {
builder.createWorld();
builder.createMountains(); return builder.getWorld();
}

什么?连树都没有,这地方白雪公主可不想去。

前面说过WorldCreator本身并不能创造世界,因为它是虚的,它的子类才做了实际的工作。来看一个简单的子类LovelyWorldCreator实现:

 class LovelyWorldCreator : public WorldCreator {
public:
LovelyWorldCreator() { _currentWorld = ; } virtual void createWorld();
virtual void createMountains(int);
virtual void createPlants(int);
virtual void createBuildings(int); virtual World* getWorld() { return _currentWorld; }
private:
World* _currentWorld;
}; void LovelyWorldCreator::createWorld() {
_currentWorld = new World();
} void LovelyWorldCreator::createMountains(int m) {
if ( !_currentWorld->hasMountains(m) ) {
Mountains* mountains = new Mountains(m);
_currentWorld->addMountains(mountains);
}
} void LovelyWorldCreator::createPlants(int p) {
if ( !_currentWorld->hasPlants(p) ) {
Plants* plants = new Plants(p);
_currentWorld->addPlants(plants);
}
} void LovelyWorldCreator::createBuildings(int b) {
if ( !_currentWorld->hasBuildings(b) ) {
Buildings* buildings = new Buildings(b);
_currentWorld->addBuildings(buildings);
}
}

LovelyWorldCreator

这里createWorld先创造了一个空的世界,然后createMountains, createPlants, createBuildings 分别为这可爱的世界添加了山、树以及建筑物。现在,Mage终于可以用createWorld和LovelyWorldCreator来创造一个平行世界了:

 Mage I;
LovelyWorldCreator spell;
World* world = I.createWorld(spell);

美丽的白雪公主如愿以偿地住进了可爱的世界。当然,还有那些霍比特人们。

特点总结

啊,对了,差点忘了说,正因为我们采用了Builder模式(似乎刚跑题了会,赶紧拉回来),将World的构建从World本身的构造函数中分离出来,由WorldCreator封装了统一的创造过程,但是却能通过子类比如LovelyWorldCreator等来创造不同表现形式。这正是Builder设计模式的特点之一。总结说来,Builder模式有如下几个特点:

  1. 它使我们可以改变一个产品的内部表示。由于Builder对象提供的是一个抽象接口,这个接口可以使生成器隐藏这个产品的表示和内部结构。所以如果要改变产品的内部结构,只需定义一个新的生成器。
  2. 它将构造代码和表示代码分开。Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。每个ConcreteBuilder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。
  3. 它使我们可以对构造过程进行更精细的控制。Builder模式是在导向者的控制下一步一步构造产品的,仅当该产品完成时导向者才从生成器中取回它。因此Builder相比其他创建型模式能更好的反映产品的构造过程。

写在最后

今天的笔记就到这里了,欢迎大家批评指正!如果觉得可以的话,好文推荐一下,我会非常感谢的!

[学习笔记]设计模式之Builder的更多相关文章

  1. [学习笔记]设计模式之Abstract Factory

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在上篇笔记Builder设计模式中,时の魔导士祭出了自己的WorldCreator.尽管它因此能创造出一个有山有树有房子的世界,但是白 ...

  2. [学习笔记]设计模式之Adapter

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 Adapter(适配器)模式主要解决接口不匹配的问题.为此,让我们要回到最初Builder模式创建平行世界时,白雪公主和小霍比特人的谜 ...

  3. [学习笔记]设计模式之Prototype

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在笔记Builder模式中,我们曾见到了最初用于创建平行世界的函数createWorld,并且它是Mage类的成员函数(毕竟是专属于魔 ...

  4. [学习笔记]设计模式之Proxy

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 “魔镜啊魔镜,谁是这个世界上最美丽的人?” 每到晚上,女王都会问魔镜相同的问题(见Decorator模式).这是她还曾身为女巫时留下的 ...

  5. [学习笔记]设计模式之Bridge

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 “魔镜啊魔镜,谁是这个世界上最美丽的人?”月光中,一个低沉的声音回荡在女王的卧室.“是美丽的白雪公主,她正和小霍比特人们幸福快乐地生活 ...

  6. [学习笔记]设计模式之Command

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 在上篇Chain of Responsibility(职责链)模式笔记中,我们学习了一种行为型设计模式.今天,我们继续这一主题,来学习 ...

  7. [学习笔记]设计模式之Chain of Responsibility

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 最近时间比较紧,所以发文的速度相对较慢了.但是看到园子里有很多朋友对设计模式感兴趣,我感觉很高兴,能够和大家一起学习这些知识. 之前的 ...

  8. [学习笔记]设计模式之Composite

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 在Composite(组合)模式中,用户可以使用多个简单的组件以形成较大的组件,而这些组件还可能进一步组合成更大的.它重要的特性是能够 ...

  9. [学习笔记]设计模式之Flyweight

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 Flyweight(享元)模式运用共享技术,可以有效地支持大量细粒度的对象.今天我们会去参观小霍比特人们的酿酒工坊……等等,不是享元模 ...

随机推荐

  1. 几个常用方法有效优化ASP.NET的性能

    一. 数据库访问性能优化 1),数据库的连接和关闭 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源.ASP.NET中提供了连 ...

  2. JavaScript获取非行间样式/定义样式

    html节点的样式分为以下几种 (1)浏览器默认样式 (2)引用样式(引用外部css文件的样式.style标签内定义的样式) 引用外部css样式:<link rel="styleshe ...

  3. node-mongodb-native的几种连接数据库的方式

    h1,h2,h3,h4,h5,h6,p,blockquote { margin: 0; padding: 0;}body { font-family: "Helvetica Neue&quo ...

  4. echo和print语句

    在php中,有两种基本的输出方法:echo  和  print echo 和 print 之间的差异: echo——能够输出一个以上的字符串,无返回值 print——只能输出一个字符串,并始终返回值为 ...

  5. PHP框架原理

    本文主要来聊聊框架理论,但不针对任何一款框架,不过任何一款框架都离不开这个理论,首先我们了解下框架的来龙去脉,任何技术的出现都是为了解决某个问题,之前的博客有讲过smarty,其存在就是为了html和 ...

  6. armv7a-mediatek451_001_vfp-linux-gnueabi-gcc: directory: No such file or directory 编译error

    release/vm_linux/output/hisense_android/mt5399_cn_android_JB/rel/obj/oss/source/arm_mali_ko/mali400- ...

  7. Docker系列

    Docker学习系列(五):Dockerfile文件 什么是Dockerfile? 它是一个名称为Dockerfile的文件 它是一个脚本文件,由一系列命令和参数构成 Dockerfile是自动构建d ...

  8. Linux Screen命令使用

    参考URL: http://jingyan.baidu.com/article/295430f128d8ea0c7e005089.html ~~~~~~~~~~~~~~~~~~~~~~~~ 其它的不提 ...

  9. 【BZOJ 3387】 线段树= =

    57 跨栏训练为了让奶牛参与运动,约翰建造了 K 个栅栏.每条栅栏可以看做是二维平面上的一条线段,它们都平行于 X 轴.第 i 条栅栏所覆盖的 X 轴坐标的区间为 [ Ai,Bi ], Y 轴高度就是 ...

  10. 利用TEA算法进行数据加密

    TEA(Tiny Encryption Algorithm)是一种小型的对称加密解密算法,最初是由剑桥计算机实验室的 David Wheeler 和 Roger Needham 在 1994 年设计. ...