装饰者模式的分析

来源:互联网 发布:cad mac中文破解版2016 编辑:程序博客网 时间:2024/04/30 05:18

先从装饰者模式的由来来讲起

如果我们要做一个游戏中的角色,要添加武器,鞋子,衣服等等,最简单的设计方法

方案1:

class Hero{private:string m_name;public:Hero(string name):m_name(name){cout<<m_name;}void WearShirt();//穿衣服  void WearWeapons();    //装备武器 void WearShoes();      //穿鞋子/*等等的方法*/ };
所以调用起来这样

Hero obj("li");obj.WearShirt();obj.WearWeapons();obj.WearShoes();
总结这个方法:如果我要加一个之前没想过的操作的话,我就得直接到类里面去改动,这已经违背了开放-封闭的原则(对于扩展是开放的,但是更改应该是闭合的),这样重用性很差,稍微大一点的项目就容易乱套。

既然这样不好,我们应该把武器,鞋子这些抽象成一个抽象类,这些用不同的装备去继承它,所以

方案2:


class Hero{private:string m_name;public:Hero(string name):m_name(name){cout<<m_name;}};class Equipment//装备的抽象接口 {public: virtual void Euip() = 0; };/*下面为子类*/ class Shirt : public Equipment//衬衣 {public:virtual void Euip();}; void Shirt :: Euip(){cout << "+穿衬衫";}class Weapons : public Equipment //武器 { public:virtual void Euip();};void Weapons ::Euip(){cout << "+装备武器";} class Shoes   : public Equipment //鞋子 {public:virtual void Euip();};    void Shoes ::Euip()  {  cout << "+穿鞋子";  } 
这样调用的话

Hero obj("LI");Equipment *pshirt     = new Shirt;Equipment *pweapons   = new Weapons;Equipment *pshoes     = new Shoes;pshirt->Euip();pweapons->Euip();pshoes->Euip();
这里的感觉上是对了,但是这样的写法是有问题的,现在的做法就像是一件件武器显示出来,他的装备是在大家面前一步步把武器,鞋子,衬衫穿上,很不符合常理,正常的应该是再类的内部穿好再展示出来。

所以下面有了装饰模式,听听名字就应该很合适

先给出类设计图


这个整个的类图,

再上代码

class Component//所有的总类 {public: virtual void Euip() = 0; };class Hero : public Component {private:string m_name;public:Hero(string name):m_name(name){cout<<m_name;}virtual void Euip();}; void Hero::Euip() { cout << "LI"; }//装备的抽象接口class EquipDecorator : public Component {private:Component *pcomponet;public:virtual void Euip();void Decprate(Component *p){this->pcomponet = p;} };void EquipDecorator::Euip(){if(pcomponet != NULL){pcomponet->Euip();}}/*下面为子类*/ class Shirt : public EquipDecorator//衬衣 {private:string m_color;public:Shirt(string color):m_color(color){};virtual void Euip();}; void Shirt :: Euip(){EquipDecorator::Euip();//先让之前的装备装起来 cout << "+穿" << m_color << "的衬衫";//执行子类动作 }class Weapons : public EquipDecorator //武器 {private:string m_length; public:Weapons(string length):m_length(length){};virtual void Euip();};void Weapons ::Euip(){EquipDecorator::Euip();//先让之前的装备装起来 cout << "+拿" << m_length << "米长的武器";//执行子类动作 } class Shoes   : public EquipDecorator //鞋子 {private:string m_speed; public:Shoes(string speed):m_speed(speed){};virtual void Euip();};  void Shoes ::Euip(){EquipDecorator::Euip();//先让之前的装备装起来 cout << "+穿速度为" << m_speed << "m/s的鞋子";//执行子类动作 } 
一口气看完,有点没看懂没关系,等一下再解释,所以客户端的调用是这样的

//创建基本对象 Hero person("LI");Shirt shirt("白色");Weapons weapons("100");Shoes shoes("20");shirt.Decprate(&person);//装饰主角 weapons.Decprate(&shirt);   //装饰装好shirt主角 shoes.Decprate(&weapons);   //装饰装好shirt和武器的主角 shoes.Euip();   //显示出来 

结果


这个时候肯定有点蒙,所以最好的是理清思路,跟着代码走一遍

 Hero person("LI");
Shirt shirt("白色");
Weapons weapons("100");
Shoes shoes("20");

这里创建主要注意的就是要先构造他自己的基类的比较简单


接下来是

shirt.Decprate(&person);//装饰主角 
weapons.Decprate(&shirt);  //装饰装好shirt主角 
shoes.Decprate(&weapons);  //装饰装好shirt和武器的主角 


这个是重点了。

shoes.Euip();  

流程为:

1.           shoes.Euip();

2.           EquipDecorator::Euip();

3.           pcomponet->Euip();(pcompnet为weapons的指针,在之前的Decprate()保存下来的)

4.           继续执行2.

5.           执行3.pcomponet->Euip();(pcompnet为shirt的指针)

6.           继续执行2.

7.       执行3.pcomponet->Euip();(pcompnet为Hero的指针)

8.          调用到了终点hero的Euip

       void Hero::Euip() { cout<<m_name; }

9.    结束7的调用,回到shirt的Euip

void Shirt :: Euip(){//已经执行了 EquipDecorator::Euip();
cout << "+穿" << m_color << "的衬衫";//执行子类动作 }

...

再一层层的向回走,把所有的添加的都输出一遍

好处和作用引用一下别人的

装饰者模式

Decorator模式(别名Wrapper):动态将职责附加到对象上,若要扩展功能,装饰者提供了比继承更具弹性的代替方案。

 

意图:

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

 

设计原则:

1. 多用组合,少用继承。

利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。

2. 类应设计的对扩展开放,对修改关闭。

 

要点:

1. 装饰者和被装饰对象有相同的超类型。

2. 可以用一个或多个装饰者包装一个对象。

3. 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的。

4. 对象可以在任何时候被装饰,所以可以在运行时动态的,不限量的用你喜欢的装饰者来装饰对象。

5. 装饰模式中使用继承的关键是想达到装饰者和被装饰对象的类型匹配,而不是获得其行为。

6. 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。在实际项目中可以根据需要为装饰者添加新的行为,做到“半透明”装饰者。

7. 适配器模式的用意是改变对象的接口而不一定改变对象的性能,而装饰模式的用意是保持接口并增加对象的职责。

 



0 0
原创粉丝点击