设计模式 笔记 生成器(建造者)模式 Builder
//---------------------------15/04/08----------------------------
//builder 生成器(建造者)模式---对象创建型模式
/*
1:意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
2:动机
3:适用性:
1>当创建复杂对象的算法应该独立于该对象的组成部分以及他们的装配方式时。
2>当构造过程必须允许被构造的对象有不同的表示时。
4:结构:
Director:
builder----------------------------->Builder:
Construct() BuildPart()
{ for all objects in structure |
{ builder->BuildPart()} } |
ConcreteBuilder: - - - ->Product
BuildPart()
GetResult()
5:参与者:
1>Builder:为创建一个Product对象的各个部件指定抽象接口。
2>ConcreteBuilder:
1)实现Builder的接口以构造和装配该产品的各个部件。
2)定义并明确它所创建的表示。
3)提供一个检索产品的接口.
3>Director:构造一个使用Builder接口的对象。
4>Product:
1)表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
2)包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
6:协作:
1>客户创建Director对象,并用它所想要的Builder对象进行配置。
2>一旦产品部件被生成,导向器就会通知生成器。
3>生成器处理导向器的请求,并将部件添加到该产品中。
4>客户从生成器中检索产品。(得到产品)
下面的图说明了Builder和Director和客户的协作:
aClient aDirector aConcreteBuilder
| | |
new ConcreteBuilder---------------------------->|
new Director(aCon..)--->| |
| | |
Construct()------------>|BuildPartA()---------->|
| BuildPartB()----------->|
| BuildPartC()----------->|
| | |
GetResult()------------------------------------>|
| | |
7:效果:
1>它使你可以改变一个产品的内部表示。
Builder给Director只提供了抽象接口,隐藏了内部装配过程,所以想要改变
内部表示的时候,只需要定义一个新的Builder就行了。
2>它将构造代码和表示代码分开。
ConcreteBuilder已经提供了创建一个产品的所有代码,不同的Director可以复用它
以在相同部件集合的基础上构造不同的Product。
3>它使你可以对构造过程进行更精密的控制。
与一下子就生产产品的创建型模式不同,Builder模式是在导向者的控制下一步一步构造产品的。
所以可以更精细地控制构造过程。
8:实现:
1>要有一个抽象的Builder类为Director提供产品每一个部分创建的接口。ConcreteBuilder
只用对感兴趣的部分实现操作就行。
2>装配和构造接口:Builder类的接口必须足够普遍。
有一个需要考虑的点是,Builder创建PartB时可能需要用到PartA的对象,
所以,可以从PartA那里返回一个PartA对象,再由Director传入PartB。
3>为什么产品没有抽象类:一般生存器生成的产品的表示相差十分之大,以至于难以提供公共父类。
9:代码示例: */
//定义一个抽象类,接口都是空操作,不声明成纯虚函数是因为ConcreteBuilder只需要实现自己感兴趣的接口
class MazeBuilder
{
public:
virtual void BuildMaze(){}
virtual void BuildRoom(int room) {}
virtual void BuildDoor(int roomFrom,
int roomTo){}
virtual Maze* GetMaze(){return
;}
protected:
MazeBuilder();
};
//Director,根据传入的Builder创建迷宫
Maze* MazeGame::CreateMaze(MazeBuilder& builder)
{
//这里想怎么创建就怎么创建,无需关注底部实现细节
builder.BuildMaze();
builder.BuildRoom();
builder.BuildRoom();
builder.BuildDoor(,
);
return builder.GetMaze();
}
class StandardMazeBuilder :
public MazeBuilder
{
public:
StandardMazeBuilder();
virtual void BuildMaze();
virtual void BuildRoom(int);
virtual void BuildDoor(int,
int);
virtual Maze* GetMaze();
private:
Direction CommonWall(Room*, Room*);
Maze* _currentMaze;
};
//具体的builder
StandardMazeBuilder::StandardMazeBuilder()
{
_currentMaze =
;
}
void StandardMazeBuilder::BuildMaze()
{
_currentMaze =
new Maze;
}
Maze* StandardMazeBuilder::GetMaze()
{
return _currentMaze;
}
void StandardMazeBuilder::BuildRoom(int n)
{
if(!_currentMaze->RoomNo(n))
{
Room* room =
new Room(n);
_currentMaze->AddRoom(room);
room->SetSide(North,
new Wall);
room->SetSide(South,
new Wall);
room->SetSide(East,
new Wall);
room->SetSide(West,
new Wall);
}
}
void StandardMazeBuilder::BuildDoor(int n1,
int n2)
{
Room* r1 = _currentMaze->RoomNo(n1);
Room* r2 = _currentMaze->roomNo(n2);
Door* d =
new Door(r1, r2);
r1->SetSide(CommonWall(r1,r2), d);
r2->SetSide(CommonWall(r2,r1), d);
}
//如果我们需要有个个会爆炸的门可以如下实现。
void StandardMazeBuilder::BuildBoomedDoor(int n1,
int n2)
{
Room* r1 = _currentMaze->RoomNo(n1);
Room* r2 = _currentMaze->roomNo(n2);
Door* d =
new BoomedDoor(r1, r2);
r1->SetSide(CommonWall(r1,r2), d);
// 感觉CommonWall实现为room的成员函数更好,r1.CommonWall(r2)这样更好理解
r2->SetSide(CommonWall(r2,r1), d);
}
//十分简单
Maze* maze;//Product
MazeGame game;//Director
StandardMazeBuilder builder;//Builder
game.CreateMaze(builder);
maze = builder.GetMaze();
//上面的两句可以合并成:
maze = game.CreateMaze(builder);
//因为create的实现里已经调用GetMaze了
class CountingMazeBuilder :
public MazeBuilder
{
public:
CountingMazeBuilder();
virtual void BuildMaze();
virtual void BuildRoom(int);
virtual void BuildDoor(int,
int);
virtual void AddWall(int, Director);
void GetCounts(int&,
int&) const;
private:
int _doors;
int _rooms;
};
CountingMazeBuilder::CountingMazeBuilder():_rooms(), _doors()
{
//_rooms = _doors = 0;
应该使用初始化列表初始化
}
inline
void CountingMazeBuilder::BuildRoom(int)
{
++_rooms;
}
inline
void CountingMazeBuilder::BuildDoor(int)
{
++_doors;
}
inline CountingMazeBuilder::GetCounts(int& rooms,
int& doors) const
{
rooms = _rooms;
doors = _doors;
}
//这就是一个计数的builder,感觉如果需要计数,直接放在基类里就行了,
想用的时候调用基类的方法一次就好。
设计模式 笔记 生成器(建造者)模式 Builder的更多相关文章
- 设计模式系列之建造者模式(Builder Pattern)——复杂对象的组装与创建
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 【原】iOS设计模式之:建造者模式Builder Pattern,用于改进初始化参数
本文主要讨论一下iOS中的Builder Pattern.与网上很多版本不同,本文不去长篇大论地解释建造者模式的概念,那些东西太虚了.设计模式这种东西是为了解决实际问题的,不能为了设计模式而设计模式, ...
- iOS设计模式之:建造者模式Builder Pattern,用于改进初始化参数
转自:http://www.cnblogs.com/wengzilin/p/4365855.html 本文主要讨论一下iOS中的Builder Pattern.与网上很多版本不同,本文不去长篇大论地解 ...
- IOS设计模式浅析之建造者模式(Builder)
定义 "将一个复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的表现". 最初的定义出现于<设计模式>(Addison-Wesley,1994). 看这个概 ...
- Net设计模式实例之建造者模式(Builder Pattern)
一.建造者模式简介(Brief Introduction) 建造者模式(Builder Pattern),将一个复杂对象的构建与它的表示分离,使的同样的构建过程可以创建不同的表示. 建造者模式的优点是 ...
- 设计模式学习之建造者模式(Builder,创建型模式)(6)
假如我们需要建造一个房子,并且我们也不知道如何去建造房子,所以就去找别人帮我们造房子 第一步: 新建一个房子类House,里面有房子该有的属性,我们去找房子建造者接口HouseBuilder,我们要建 ...
- 设计模式—建造者模式(Builder)
title: 设计模式-建造者模式 建造者模式(Builder)是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节.建造者模式属于对 ...
- 乐在其中设计模式(C#) - 建造者模式(Builder Pattern)
原文:乐在其中设计模式(C#) - 建造者模式(Builder Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 建造者模式(Builder Pattern) 作者:webabc ...
- 【设计模式】建造者模式 Builder Pattern
前面学习了简单工厂模式,工厂方法模式以及抽象工厂模式,这些都是创建类的对象所使用的一些常用的方法和套路, 那么如果我们创建一个很复杂的对象可上面的三种方法都不太适合,那么“专业的事交给专业人去做”,2 ...
随机推荐
- 使用 D: 盘作为 Windows VM 上的数据驱动器
如果应用程序需要使用 D 盘存储数据,请按照以下说明使用其他驱动器号作为临时磁盘. 切勿使用临时磁盘来存储需要保存的数据. 如果调整虚拟机大小或停止(解除分配)虚拟机,这可能会触发将虚拟机放置于新虚拟 ...
- 一次失败的生产系统中AlwaysOn AG切换经历
14:25分左右,某数据库主副本服务器崩溃报错,在数据库无法接收SQL语句进行调整的情况下重启了主副本服务器. 由于服务器重启时间会比较长,为了保证主副本服务器重启期间数据库能正常进行写入,强制将主库 ...
- Android图形显示之硬件抽象层Gralloc【转】
https://blog.csdn.net/yangwen123/article/details/12192401 FrameBuffer驱动程序分析文中介绍了Linux系统下的显示驱动框架,每个显示 ...
- Linux 补丁生成与使用
我们在升级Linux 内核的时候,难免会接触到补丁的知识.下面对如何生成补丁和如何打补丁作讲解. 生成补丁: 制作 hello.c 和 hello_new.c 两个文件如如下所示. ➜ diff ls ...
- UI中新增一个右击按钮的过程
1.首先给出增加之后的成品 点击后的界面 3.需要增加的部分 新增一个类:DiglogAddUser 用于操作用户填写的数据,写入数据库等操作 3.1首先在资源文件中定义窗口代号 3.2 枚举出该代 ...
- 13.1SolrCloud集群使用手册之Collections API
转载请出自出处:http://www.cnblogs.com/hd3013779515/ 1.创建collection name:指明collection名字 router.name:指定路由策略,默 ...
- 微信支付的notify.php中如何获取订单号(php版)
不要直接使用demo中的notify.php,重写notify.php,继承WxPayNotify(可参考微信api),具体如下: require_once "WxPay.Api.php&q ...
- Docker技术入门与实战 第二版-学习笔记-9-Docker Compose 项目-3-Django项目实例
使用 Django 我们现在将使用 Compose 配置并运行一个 Django/PostgreSQL 应用.在此之前,先确保 Compose 已经安装. 1.通过编辑 Dockerfile文件来指定 ...
- Tornado框架实现异步爬虫
from urllib.parse import urljoin from bs4 import BeautifulSoup from tornado import gen, httpclient, ...
- $LCT$初步
\(\rm{0x01}\) 闲话 · \(LCT\)的用途以及具体思路 LCT是啥?百度一下的话--貌似是一种检查妇科病的东西?Oier的口味可是真不一般啊 咳,其实在我最近只是浅浅地学了一部分的基础 ...