[学习笔记]设计模式之Builder
写在前面
为方便读者,本文已添加至索引:
设计模式
学习笔记索引
作为一个新入职的魔导士呢,哦不,是程序员,我以为并没有太多机会去设计项目的软件架构。但是,工作一段时间之后,自己渐渐意识到,哪怕是自己要去做的小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模式有如下几个特点:
- 它使我们可以改变一个产品的内部表示。由于Builder对象提供的是一个抽象接口,这个接口可以使生成器隐藏这个产品的表示和内部结构。所以如果要改变产品的内部结构,只需定义一个新的生成器。
- 它将构造代码和表示代码分开。Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。每个ConcreteBuilder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。
- 它使我们可以对构造过程进行更精细的控制。Builder模式是在导向者的控制下一步一步构造产品的,仅当该产品完成时导向者才从生成器中取回它。因此Builder相比其他创建型模式能更好的反映产品的构造过程。
写在最后
今天的笔记就到这里了,欢迎大家批评指正!如果觉得可以的话,好文推荐一下,我会非常感谢的!
[学习笔记]设计模式之Builder的更多相关文章
- [学习笔记]设计模式之Abstract Factory
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在上篇笔记Builder设计模式中,时の魔导士祭出了自己的WorldCreator.尽管它因此能创造出一个有山有树有房子的世界,但是白 ...
- [学习笔记]设计模式之Adapter
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 Adapter(适配器)模式主要解决接口不匹配的问题.为此,让我们要回到最初Builder模式创建平行世界时,白雪公主和小霍比特人的谜 ...
- [学习笔记]设计模式之Prototype
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在笔记Builder模式中,我们曾见到了最初用于创建平行世界的函数createWorld,并且它是Mage类的成员函数(毕竟是专属于魔 ...
- [学习笔记]设计模式之Proxy
为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 “魔镜啊魔镜,谁是这个世界上最美丽的人?” 每到晚上,女王都会问魔镜相同的问题(见Decorator模式).这是她还曾身为女巫时留下的 ...
- [学习笔记]设计模式之Bridge
写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 “魔镜啊魔镜,谁是这个世界上最美丽的人?”月光中,一个低沉的声音回荡在女王的卧室.“是美丽的白雪公主,她正和小霍比特人们幸福快乐地生活 ...
- [学习笔记]设计模式之Command
为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 在上篇Chain of Responsibility(职责链)模式笔记中,我们学习了一种行为型设计模式.今天,我们继续这一主题,来学习 ...
- [学习笔记]设计模式之Chain of Responsibility
为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 最近时间比较紧,所以发文的速度相对较慢了.但是看到园子里有很多朋友对设计模式感兴趣,我感觉很高兴,能够和大家一起学习这些知识. 之前的 ...
- [学习笔记]设计模式之Composite
为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 在Composite(组合)模式中,用户可以使用多个简单的组件以形成较大的组件,而这些组件还可能进一步组合成更大的.它重要的特性是能够 ...
- [学习笔记]设计模式之Flyweight
为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 Flyweight(享元)模式运用共享技术,可以有效地支持大量细粒度的对象.今天我们会去参观小霍比特人们的酿酒工坊……等等,不是享元模 ...
随机推荐
- 用javascript操作xml(二)JavaScript 将XML转换成字符串(xml to string)
function xmlToString(xmlData) { var xmlString; //IE if (window.ActiveXObject){ xmlString = xmlData.x ...
- LFS实践
用了三天,编译了两次LFS,把LFS的基本流程和原理都弄清了.用的是LFS 6.3,使用的教程是LFS速成手册(6.3) ,感觉很不错,如果按照它的做法,一步一步来,基本都能编译成功而且没什么错误.不 ...
- lucene 实现word,pdf全文检索源码
创建索引: import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import jav ...
- python类库26[web2py之基本概念]
一 web2py的应用的执行环境Models,Controllers和views所在的执行环境中,以下对象已经被默认地导入: Global Objects: request,response,ses ...
- jQuery获取屏幕的宽度
Javascript: 网页可见区域宽: document.body.clientWidth网页可见区域高: document.body.clientHeight网页可见区域宽: document.b ...
- Android 观察系统中短信内容的变化(内容观察者)
//内容观察者(如果系统的短信发生了变化,比如刚获取一条短信,那么将触发onChange方法) ContentResolver contentResolver = getContentResolver ...
- X86汇编快速入门
http://www.cnblogs.com/YukiJohnson/archive/2012/10/27/2741836.html
- android视频播放
视频播放我们用到的是MediaPlayer,显示控件使用的surfaceView 我们向SD卡中先添加个视频文件,我的是xajh.3gp,不要用mp4,MP4会出现 should have subti ...
- java线程(1)-线程同步
Java提供了两种创建线程方法: 通过实现Runable接口: 通过继承Thread类本身. 线程同步 为何使用同步? java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的 ...
- Custom ASP.NET Application into SharePoint --整合ASP.NET应用程序到SharePoint
转:http://www.devexpertise.com/2009/02/18/integrating-a-custom-aspnet-application-into-sharepoint-par ...