设计模式-生成器模式
2012-10-22 17:31
148 查看
前两个文章我介绍了工厂方法模式和抽象工厂模式,这次我来讲一些生成器模式。生成器模式我也用的比较多。5个创建型模式里面,我比较喜欢用工厂方法模式,生成器模式和单例模式。
意图
将一个复杂对象的构建与它的表示分开,使得同样的构建过程可以创建不同的表示。
结构图
一眼看去是不是和抽象工厂模式有点像?是啊,我也觉得很像,有什么分别呢?别急,让我先讲一下builder 模式是怎么实现的。
为了更好的来解释生成器模式,我这里还画了个序列图,这个序列图清楚地描述了客户端是如何来使用生成器的。
我们还是以之前讲过的跑酷游戏的地形为例。先给出所有相关类的图:
产品类,没有变化,直接给出代码:
然后是关键的Builder类,首先我们抽象一个CBuilder类:
里面有3个接口:
1. 创建一个背景实例,构建CTerrain对象的背景;
2. 创建一个地面实例,构建CTerrain对象的地面;
3. 返回一个CTerrain实例(Terrain由背景和地面组成)
注意这3个函数里面,只有第三个函数才返回一个CTerrain实例,另外2个函数都不返回任何东西。
接下来让我们看看CBuilder的一个具体实现子类:
从代码里面可以看到,我们在CSnowTerrainBuilder里面增加了一个CTerrain*的数据成员。也就是说CSnowTerrainBuilder聚合了一个CTerrain对象。
MakeBackground()和MakeGround()生成了2个CTerrain的组件,并且把生成的组件放到CTerrain对象里面(也就是构建CTerrain对象)。
下面我们来看一下CCreator类(也就是Builder模式里面的Director)
这个函数跟抽象工厂里面的那个函数很像,但是我们可以发现,抽象工厂CCreator::Create()里面的其中4行代码在生成器模式里面并没有:
哈哈,看一下CSnowTerrainBuilder的代码就明白了,原来这些代码跑到CSnowTerrainBuilder里面去了。也也就是生成器模式的一个特点,把对象的构建给分离出去了(这些构建代码跑到Builder类里面去了)。
然后再看一下生成器模式的CCreator::Create(),我们会发现CCreator并不知道CTerrain的内部表示(MakeBackground和MakeGround并没有返回任何东西)。从接口名字也许可以知道Builder在创建背景和地面实例,但是并不知道具体在创建什么实例。从类图的角度讲生成器模式的Director(CCreator)类并不依赖于背景类和地面类。而抽象工厂模式却是依赖的。用G4的说法就是:生成器隐藏了对象CTerrain的内部表示。这就使得改变CTerrain的内部表示要容易一些,因为所有CBuilder的客户都不需要被改变。
最后看看客户端是怎么调用的:
相当的easy。
假如要build一个新的地形,比如森林地形,很简单,增加一个CBuilder的子类:CForestTerrainBuilder,然后在客户端里面创建一个CForestTerrainBuilder的对象,传给CCreator就ok了。
好了,生成器模式基本介绍完毕。文章的开始我们就讲了生成器模式和抽象工厂模式很像。那么到底有什么分别呢?
我们可以总计一下:
1. 抽象工厂模式的工厂类提供了一系列创建对象的接口,这些接口里面仅仅创建对象,而没有任何构建的动作。而生成器模式的builder类里面提供的接口实现了对象的构建。
2. 抽象工厂模式的工厂类的每一个接口都返回一个对象。而生成器模式的builder类的接口里面,只有一个函数返回最后构建完毕的对象,其他所有的接口并不返回任何东西。
3. 生成器模式着重于一步一步构造一个复杂对象。而抽象工厂模式着重于多个系列的产品对象(简单或者复杂的)。
4. 生成器模式在最后一步才返回产品,而抽象工厂模式是立即返回。
我个人的习惯就是当一个对象比较复杂的时候,比如这个对象有很多其他对象组成,然后这些组成相对比较容易会变动时,用Builder模式比较合适。
意图
将一个复杂对象的构建与它的表示分开,使得同样的构建过程可以创建不同的表示。
结构图
一眼看去是不是和抽象工厂模式有点像?是啊,我也觉得很像,有什么分别呢?别急,让我先讲一下builder 模式是怎么实现的。
为了更好的来解释生成器模式,我这里还画了个序列图,这个序列图清楚地描述了客户端是如何来使用生成器的。
我们还是以之前讲过的跑酷游戏的地形为例。先给出所有相关类的图:
产品类,没有变化,直接给出代码:
class CComponent { public: virtual void LoadPicture() = 0; }; class CTerrain { public: virtual void SetBackground(CComponent* bg) { if (m_BackGround) { delete m_BackGround; } m_BackGround = bg; } virtual void SetGround(CComponent* ground) { if (m_Ground) { delete m_Ground; } m_Ground = ground; } CTerrain() { m_BackGround = NULL; m_Ground = NULL; } virtual ~CTerrain() { if (m_BackGround) { delete m_BackGround; m_BackGround = NULL; } if (m_Ground) { delete m_Ground; m_Ground = NULL; } } protected: CComponent* m_BackGround; CComponent* m_Ground; }; class CSnowBackground: public CComponent { public: virtual void LoadPicture() { std::cout<< "Load snow background picture \n"; } }; class CSnowGround: public CComponent { public: virtual void LoadPicture() { std::cout<< "Load snow ground picture\n"; } };
然后是关键的Builder类,首先我们抽象一个CBuilder类:
class CBuilder { public: virtual void MakeBackground() = 0; virtual void MakeGround() = 0; virtual CTerrain* GetTerrain() = 0; };
里面有3个接口:
1. 创建一个背景实例,构建CTerrain对象的背景;
2. 创建一个地面实例,构建CTerrain对象的地面;
3. 返回一个CTerrain实例(Terrain由背景和地面组成)
注意这3个函数里面,只有第三个函数才返回一个CTerrain实例,另外2个函数都不返回任何东西。
接下来让我们看看CBuilder的一个具体实现子类:
class CSnowTerrainBuilder: public CBuilder { public: virtual void MakeBackground() { CComponent* bk = new CSnowBackground(); bk->LoadPicture(); _Terrain->SetBackground(bk); } virtual void MakeGround() { CComponent* ground = new CSnowGround(); ground->LoadPicture(); _Terrain->SetGround(ground); } virtual CTerrain* GetTerrain() { return _Terrain; } CSnowTerrainBuilder() { _Terrain = new CTerrain(); } protected: CTerrain* _Terrain; };
从代码里面可以看到,我们在CSnowTerrainBuilder里面增加了一个CTerrain*的数据成员。也就是说CSnowTerrainBuilder聚合了一个CTerrain对象。
MakeBackground()和MakeGround()生成了2个CTerrain的组件,并且把生成的组件放到CTerrain对象里面(也就是构建CTerrain对象)。
下面我们来看一下CCreator类(也就是Builder模式里面的Director)
class CCreator { public: virtual CTerrain* Create(CBuilder& builder) { builder.MakeBackground(); builder.MakeGround(); return builder.GetTerrain(); } };
这个函数跟抽象工厂里面的那个函数很像,但是我们可以发现,抽象工厂CCreator::Create()里面的其中4行代码在生成器模式里面并没有:
class CCreator { public: void Create(CFactory& factory, CTerrain** t, CWeather** w) { CTerrain* terrain = factory.MakeTerrain(); CComponent* bg = factory.MakeBackground(); CComponent* ground = factory.MakeGround(); //下面这4行代码并没有出现在Builder模式的版本里面,哪里去了呢? bg->LoadPicture(); ground->LoadPicture(); terrain->SetBackground(bg); terrain->SetGround(ground); CWeather* weather = factory.MakeWeather(); *t = terrain; *w = weather; } };
哈哈,看一下CSnowTerrainBuilder的代码就明白了,原来这些代码跑到CSnowTerrainBuilder里面去了。也也就是生成器模式的一个特点,把对象的构建给分离出去了(这些构建代码跑到Builder类里面去了)。
然后再看一下生成器模式的CCreator::Create(),我们会发现CCreator并不知道CTerrain的内部表示(MakeBackground和MakeGround并没有返回任何东西)。从接口名字也许可以知道Builder在创建背景和地面实例,但是并不知道具体在创建什么实例。从类图的角度讲生成器模式的Director(CCreator)类并不依赖于背景类和地面类。而抽象工厂模式却是依赖的。用G4的说法就是:生成器隐藏了对象CTerrain的内部表示。这就使得改变CTerrain的内部表示要容易一些,因为所有CBuilder的客户都不需要被改变。
最后看看客户端是怎么调用的:
CSnowTerrainBuilder builder; CCreator creator; creator.Create(builder); CTerrain* snowTerrain = builder.GetTerrain();//snowTerrain 就是builder创建出来的地形实例 //这里可以用snowTerrain来做一些其他的事情 delete snowTerrain;
相当的easy。
假如要build一个新的地形,比如森林地形,很简单,增加一个CBuilder的子类:CForestTerrainBuilder,然后在客户端里面创建一个CForestTerrainBuilder的对象,传给CCreator就ok了。
好了,生成器模式基本介绍完毕。文章的开始我们就讲了生成器模式和抽象工厂模式很像。那么到底有什么分别呢?
我们可以总计一下:
1. 抽象工厂模式的工厂类提供了一系列创建对象的接口,这些接口里面仅仅创建对象,而没有任何构建的动作。而生成器模式的builder类里面提供的接口实现了对象的构建。
2. 抽象工厂模式的工厂类的每一个接口都返回一个对象。而生成器模式的builder类的接口里面,只有一个函数返回最后构建完毕的对象,其他所有的接口并不返回任何东西。
3. 生成器模式着重于一步一步构造一个复杂对象。而抽象工厂模式着重于多个系列的产品对象(简单或者复杂的)。
4. 生成器模式在最后一步才返回产品,而抽象工厂模式是立即返回。
我个人的习惯就是当一个对象比较复杂的时候,比如这个对象有很多其他对象组成,然后这些组成相对比较容易会变动时,用Builder模式比较合适。
相关文章推荐
- 再次研究设计模式 第二章 生成器
- 设计模式之桥接生成器责任链蝇量解释器
- 【初学设计模式】Builder (生成器)
- 不懂接口、反射、委托、设计模式足足写了5年的代码 -- 写给初学者(谈美女生成器不谈代码生成器)
- 设计模式学习--------9.生成器模式学习
- 设计模式 3.2 Builder(生成器)对象创建型模式
- 【设计模式】创建型模式之生成器Builder
- 设计模式--生成器模式
- 设计模式-创建型-builder生成器
- java设计模式之生成器模式
- 设计模式:(3)生成器模式 (Builder)
- Java设计模式:九、生成器模式
- c++ 设计模式之创建者(生成器)模式
- 设计模式-生成器模式
- 设计模式----Builder(生成器)模式
- 生成器模式——设计模式系列
- java设计模式学习—生成器(Builder)
- 设计模式之生成器(Builder)----对象创建型模式
- 设计模式——单例,原型,生成器
- 生成器(Builder)设计模式