| xhliu's profile青蛙王子的工作空间PhotosBlogLists | Help |
There are no categories in use.
|
December 21 设计模式,7种构造型模式举例在遥远的过去,有这么一个与世无争的小村子,村里有一个村长(A)和很多的村民(Bs). 围绕着这个小村子,发生了无数的可歌可泣的故事.当然,和其他的故事一样,村子之外有一个可恶的皇帝(E).
1) 皇帝要让所有的村民交租子,他要经历下面的流程: a) 他首先跑到村民b1那里收租子,村民b1的家里只有门,他就从门进入。 b) 他又跑到村民b2那里收租子,村民b2家里只有窗,没有门,他就从窗进入。 c) 村民b3家里门也没有,窗也没有,皇帝只好采用直升飞机空降的方式进入。 d) 。。。。 终于有一天,皇帝再也受不了了,他把村长叫过来,对他说:以后我收租子,只找你一个,从门进入,我收谁的你就跑腿。从此之后,可怜的村长就成了跑腿的人。皇帝很高兴,他把自己的创意称之为FACADE 2) 时光如梭。老村长不停的跑腿,终于累死了。于是村民b3当选为村长。这年,皇帝过来收租子,发现怎么都进步去村长的家里:村长家里没有门!皇帝想,“妈妈的,总不成每次都让我用直升飞机空降来收租子吧?”邪恶的皇帝又想了一个主意,他对村民b4说:“你在村长家外面造一个房子,把他的家全部包围起来,盖一个又宽又大的门,以后我找村长就找你了”皇帝很高兴,他又不用跑腿了,他把自己的想法称之为Adapter,而村长就成了Adaptee. 3) 时间就像小风一样嗖嗖的过着。村长不停的换,而邪恶的皇帝却始终活着,但是他已经厌倦了每次为新的村长找一个Adapter。他又开始思考了。他发现村里面的村们bx和自己一样的长寿。于是他改变了自己的策略,他让bx做这样的事情:准备好村长,准备好门。每次收租子的时候,他都只需要去bx那里问一下:“现在的村长是谁?”。然后就可以了。 皇帝又胜利了,他把自己的方法称之为Bridge。 4) 有一天,邻国的女皇想到这个小村子里面参观。皇帝一看,“坏了,这些村民个个连衣服都买不起,光着屁股,我大国的威严何在阿?”于是,皇帝把自己的秘书d叫过来,对他说:“每个村民出来的时候,你给他们穿一个漂亮的衣服,别让他们给我丢脸!”最后,邻国的女皇看到的全是穿着漂亮衣服的村民。皇帝很高兴,于是他把自己的方法叫做Decorator 5) 村子越来越大,村民越来越多。终于有一天,村子分裂了,变成了两个村子。皇帝一看,每次收租子我都找两个村长,太麻烦了!于是邪恶的皇帝又有了点子:在村子之上设立乡政府,在乡政府之上设立县政府。。。 于是不管将来有多少的村民,自己都很方便管理,他把自己的方法叫做 Composite 6) 终于有一天,皇帝有了自己的王国,村门很多很多,管理起来太过于复杂。皇帝每天要处理每个村民的事情,忙的头昏脑涨的。于是,邪恶的皇帝又有点子了,他成立了一个特殊部门“东长”,然后又制定了惩罚规定,叫做“拘留,坐牢,流放,砍头”。每当有一个村民发生问题的时候,皇帝就问“东厂”:他的问题怎么办? 东厂说:坐牢。又有一个村民发生了问题,皇帝问东厂:怎么半?东厂说:他的问题以前的不行,我又发明了一种新的处理方法,叫做“凌迟”。皇帝很高兴,自己终于又可以轻轻松松的管理国家了。他把自己的方法称之为Flyweight. 7) 皇帝继续做着自己的美梦。他越来越依赖于自己的宠臣太监t了,不管有什么问题,他都问t,然后t去处理。他问t:我们有多少国民阿?t说,1000万。他问t说,我们有多少收入阿,t说1000万。其实t已经大权独揽,自己腰包里面赚了无数的10000万了。T自己偷偷的大笑:哈哈,我就是传说中的Proxy阿!! 设计模式: AdapterAdapter其实是一种封装.举例子如下:
我们有四种类
1) 苹果: public 水果
2) 梨: public 水果
3) 香蕉: public 水果
4) 玉米
而水果有一个接口,可以知道他的重量.玉米没有这样的借口.
class 水果
{
virtual int Weight();
}
在程序中遇到这样的情况,最理想的是用一个for循环来遍历所有的水果,可以分别得到他们的重量,但是,居然有玉米!!一个玉米让我们没有办法用for循环,只能用if else语句.那有没有什么方法可以解决这个问题呢? 当然有,就是我们的adapter.
这里玉米就是adaptee, 我们可以生成一个叫做 "玉米果" 的adapter,有两种方法,如下:
1) class 玉米果: public 水果,private 玉米
{
virtual int Weight();
}
2) class 玉米果: public 水果
{
private:
玉米的实例.
public:
virtual int Weight();
}
这两种方法都在程序上保证了玉米果是一个"水果",他已经不再保证他具有"玉米"的特征(私有继承和私有变量)
如果采用"class 玉米果: public 水果,public 玉米"的方法,那么就是一个双向适配器
可插入适配器: 可插入适配器的核心特征为,他不光可以为一个类做适配工作,还可以为很多类作适配工作. 比如上面的例子,我们又出现了 红薯,土豆 等等,如果我们的适配器可以满足这些操作,那么就称之为 可插入适配器.
可插入适配器需要寻找这些类的共同接口集合,或者使用proxy December 20 设计模式:5种创建模式举例为了加强对这五种创建模式的理解,我就拿电脑生产做为例子。 一个电脑包含很多组件:CPU, Disk, Monitor, keyBoard, Mouse。
当然,首先我们有5种Factory: CPUFactory, DiskFactory, MonitorFactory, KeyBoardFactory, MouseFactory。这里采用的就是Factory模式,例如CPUFactory可以有Intel, AMD等等,DiskFactory可以有Maxto, Seaga等。这几个都是电脑组件的程产厂商,对于一个电脑的组成厂商,它需要声称这几个Factory的实例,以便于每次需要一个组建的时候就可以直接生成。于是一个全球的管理全部电脑组建的Abstract Factory就出现了。 人如其名,这个抽象工厂真的是抽象的,并没有这个组织。
class CPUFactory
{
public:
virtual CPU* CreateCPU();
}
class IntelCPUFactory : public CPUFactory
{
public:
virtual CPU* CreateCPU();
}
class AMDCPUFactory: public CPUFactory
{
public:
virtual CPU* CreateCPU();
}
class MousePrototype
{
public:
virtual Mouse* CreateMouse();
}
class SingletonAbstractComputerFactory
{
virtual CPUFactory* CreateCPUFactory();
virtual DiskFactory* CreateDiskFactory();
...
virtual MousePrototype* CreateMouse();
}
显然,这个Abstract Factory只需要一个,因此它是singleton的。这样不管在世界的任何地方,我们制造一个 IntelCPUFactory,我都可以制造出来。
上面的Abstract里面CPU和Disk都是声称了一个Factory,例如可以生成IntelCPUFactory,生成MaxtoDiskFactory。而由于很多Mouse都是从一个原型里面做了一些修改,所以可以声明原型法。
有了上面的定义后,我们就可以在程序的任何地方,来得到一个CPU或者一个Disk,例如:我们在SingletonAbstractComputerFactory中只生产IntelCPU(这个可以写死在代码里面,也可以配置),如果需要生产其他新种类的CPU,只需要修改这个singleton类就可以了。
现在组建都有了,我们需要一台电脑,怎么办呢?我们可以让联想公司做这件事情,这就是builder
class Builder
{
public:
virtual void SetCPU(CPU* cpu);
virtual void SetDisk(Disk* disk);
virtual void LinkToComputer();
}
class LegendBuilder : public builder
{
public:
virtual void SetCPU(CPU* cpu);
virtual void SetDisk(Disk* disk);
virtual Computer* MakeComputer(); }这里可以看出:builder和Abstract Factory的区别,可能他们的声明都是一样的,但是做的事情不一样。Abstract Factory侧重的是创建几个东西,而builder侧重的是把已经有的几个东西组成一个新的复杂的object。所以,intel是Factory,而联想是builder。
设计模式:Abstract Factory和Builder如果说 Factory和Prototype是同一个层次的话,那么Abstract Factory和Builder就是更高一级的层次。
1 Abstact Factory
在上面的Factory类型中,我们发现如果种类变了,我们还是要修改我们的代码: Factory = new 宝马工厂。 这样的代码可能出现在很多的地方,改起来并不是很方面。那么怎么办呢? 我们能不能把修改集中在一个地方?答案是可以的,那就是Abstract Factory。我们专门生成一个类来管理工厂,把 Factory = new 宝马工厂 这句话放到他的入口里面。
class AbstractFactory
{ protected: AbstractFactory():_instance(0){} public:
virtual Factory* CreateCarFactory()
{ if(0 == _instance) { _instance = new 宝马工厂。 } return _instance; } private:
Factory* _instance; } 上面的代码实现了一个简单的singleton的Abstract Factory。这样,如果下次用户需要一个新的工厂,那么可以从这个AbstractFactory里面派生一个新的类,或者修改代码等等。
这时候,有人要问了,这种操作我们直接用Factory也可以实现阿,直接把原来 宝马工厂 的实现修改不就行了么? 当然可以,但是Abstract Factory的存在价值是 他可以支持更复杂的创建。比如一个军工厂,他生产轿车,飞机,坦克等等。其中的轿车就是我们上面说的轿车,也有很多自己的。我们就可以为军工厂实现一个自己的Abstract Factory.
class AbstractFactory
{
public:
virtual CarFactory* CreateCarFactory();
virtual TankFactory* CreateTankFactory();
virtual PlaneFactory* CreatePlaneFactory();
}
可以看出,一个Abstract Factory的价值在于它可以创建更多的工厂类。当然,他也可以创建具体的实例,prototype类,等等,甚至可以创建一个新的子AbstractFactory。 所以Abstract Factory类似一个总的管理者,管理的是各个实例的工厂。正因为如此,一个程序里面的Abstract Factory往往是singleton的。
2. builder
builder 也是一个高层建筑,但是他和Abstract Factory侧重点不同,Abstract Factory侧重于创建东西的结果,而builder侧重的是创建东西的过程。
class CarBuilder
{
public:
virtual void Setwheel();
virtual void SetMoto();
virtual void SetSeat();
virtual Car* GetCar();
}
在调用的时候采用
Car* CreateCar(CarBuilder& cb)
{
cb.SetWheel(轮子);
cb.SetMoto(马达);
cb.SetSeat(作为);
return cb.GetCar();
}
上面的例子可以看出builder的特征。 设计模式:工厂和原型1:工厂(Factory Method)
首先,工厂这个名字取得很好,就像前面说的,创建型模式的意义在于把生成一个变量从手工作坊(new,delete)的方式变化到工业化的模式,那么这里的工业化模式最典型的就是工厂(Factory Method)。工厂自己也是一个类,也会生成实例,工厂的功能就是为了创建另外一些变量。举例子,我们有奔驰车,宝马车,马拉车等等。现在我们要为他们生成变量,手工作坊和工业化的区别如下:
1) 手工作坊
MyCar = new 奔驰。
显然,如果有一天,你需要了一个新的车,叫宝马, 就需要把程序里面所有的MyCar = new 奔驰换成 MyCar = new 宝马。这样实在太麻烦了。
2) Factory方式
首先我们需要一个factory的实例 Factory = new 轿车工厂
那么我们需要奔驰车的时候就是用 MyCar = Factory.CreateCar() //这里的Factory 是奔驰车的工厂
我们需要宝马的时候就用 MyCar = Factory.CreateCar() //这里的Factory 是宝马的工厂
看,不许要修改那么多了吧?这个就是Factory模式的好处。
3) 缺点。
可惜,Factory模式并不能一点都不修改,他需要修改一部分,就是Factory自己的创建
当从Factory = new 轿车工厂 创建一个工厂的时候,必须要指定是哪个工厂。比如下面的例子
class 轿车工厂
{
}
class 宝马轿车工厂:public 轿车工厂
{
}
class 奔驰轿车工厂:public 轿车工厂
{
}
那么,当你想从宝马车换到本车车的时候,就必须有下面的变迁:
Factory = new 宝马轿车工厂 ==> Factory = new 奔驰轿车工厂
2: 原型 (Prototype)
工厂模式还是有局限性的,比如轿车,我们需要的轿车可能会越来越多:奔驰,宝马,法拉利,A,B,C,D。。。。。可能有好几百种。采用工厂模式,我们必须给每一种车辆设计一个他的工厂,这个会生成好几百个类!!!!!!!
然而,我们其实并不需要声明这么多的类,因为好多工厂都是类似的。比如上面的几百个例子中,有几个这样的例子:宝马1型,宝马2型,宝马3型,宝马4型,宝马5型,宝马6型。虽然他们的差别很小,但是Factory模式必须为他们每一个生成一个类!显然,我们可以用下面的方式来生成几个类:宝马原形, 然后 宝马1型= 宝马原形(发动机1),宝马1型= 宝马原形(发动机2)。。。
这就是原型模式!
原型模式的存在价值就是减少 Factory模式的类的种类。
原型模式有以下几点注意事项:
1) 原型能大大减少类的数目,但是并不会把上面轿车几百种变成一种,所以我们需要一个原型管理器。用associative store的方式保存,可以注册,删除,引用一个原型。这种管理器也可以是一个扩展的singleton对象,这点就有点类似Abstract Factory了,但是功能不一样。
2) 克隆操作。也就是c++里面的拷贝构造函数。同一个一个原型实现一个新的实例,必须要注意把原型拷贝到新的实例里面的操作。
|
||||
|
|