写在前面

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

作为一个新入职的魔导士呢,哦不,是程序员,我以为并没有太多机会去设计项目的软件架构。但是,工作一段时间之后,自己渐渐意识到,哪怕是自己要去做的小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. 数据库(MSSQLServer,Oracle,DB2,MySql)常见语句以及问题(续1之拼接字符串)

    上一篇文章http://www.cnblogs.com/valiant1882331/p/4056403.html写的太长了,所以就换了一篇,链接上一节继续 字符串的拼接 MySql中可以使用&quo ...

  2. 禁止选择文本和禁用右键 v2.0

    禁止鼠标右键(注:在火狐浏览器没有起到效果作用) <script> function stop() { return false }; document.oncontextmenu = s ...

  3. css(html)背景图优化合并

    图片本身的优化: 图像质量要求和图像文件大小决定你用什么格式的图片,用较小的图片文件呈现较好的图像质量. 当图片色彩过于丰富且无透明要求时,建议采用jpg格式并保存为较高质量. 当图片色彩过于丰富又有 ...

  4. linux压缩与解压缩 tar命令

    #压缩tar -czvf ***.tar.gz  filetar -cjvf ***.tar.bz2 file#解压缩tar -xzvf ***.tar.gz filetar -xjvf ***.ta ...

  5. python 输出小数控制

    一.要求较小的精度 将精度高的浮点数转换成精度低的浮点数. 1.round()内置方法round()不是简单的四舍五入的处理方式. >>> round(2.5) 2 >> ...

  6. MySQL简单使用

    1.启动MySQL服务器实际上上篇已讲到如何启动MySQL.两种方法:一是用winmysqladmin,如果机器启动时已自动运行,则可直接进入下一步操作.二是在DOS方式下运行 d:/mysql/bi ...

  7. Latex 常用知识点存档

    前言: 本篇仅作为自己的知识存档. $Latex$是什么,就不用介绍了,网上好多教程和知识点,当忘记的时候搜一下就可以了. 本科做美赛和毕设的时候用的$Latex$排版,最近开始在博客园写点东东,发现 ...

  8. int 占一个机器字长

    int与short int是不一样的. C++标准规定,int占一个机器字长.在32位系统中int占32位,也就是4个字节, 而在老式的16位系统中,int占16位,即2个字节. 而C++标准中只限制 ...

  9. Li Fei-fei写给她学生的一封信,如何做好研究以及写好PAPER

    Li Fei-fei写给她学生的一封信,如何做好研究以及写好PAPER 在微博上看到的,读完还是有些收获的,首先是端正做research的态度. 我是从这里看到的:http://www.vjianke ...

  10. NWERC 2012 Problem J Joint Venture

    刚刚开始想的是用二分的方法做,没想到这个题目这么水,直接暴力就行: 代码: #include<cstdio> #include<algorithm> #define maxn ...