转载自:
http://patmusing.blog.163.com/blog/static/135834960201002321448133/
假如我们需要为游戏开发坦克,除了各种不同型号的坦克(T50、T75和T90)外,我们还希望在不同场合中为其增加以下一种或多种功能,比如:
- 红外夜视功能
- 水陆两栖功能
- 卫星定位功能
等等,通常在不使用设计模式的情况下,大致的实现思路如下:
1. 先定义一个抽象坦克类
class Tank
{
public:
virtual void shot() = 0;
virtual void run() = 0;
public:
virtual ~Tank()
{
cout << "in the destructor of Tank..." << endl;
}
};
2. 各种型号的坦克均继承抽象坦克类
class T50 : public Tank
{
// ...
};
class T75 : public Tank
{
// ...
};
class T90 : public Tank
{
// ...
};
3. 定义各种新增功能的接口
class IInfrared // 红外功能抽象类,用作接口
{
// ...
};
class IAmphibian // 两栖功能抽象类,用作接口
{
// ...
};
class IGPS // 定位功能抽象类,用作接口
{
// ...
};
4. 定义各种具有新增功能的型号
以T50为例,定义如下:
class T50Infrared : public T50, public IInfrared // 有红外功能的T50
{
// ...
};
class T50Amphibian : public T50, public IAmphibian // 有两栖功能的T50
{
// ...
};
class T50GPS : public T50, public IGPS // 有定位功能的T50
{
// ...
};
class T50InfraredAmphibian : public T50, public IInfrared, public IAmphibian // 有红外、两栖功能的T50
{
// ...
};
class T50InfraredGPS : public T50, public IInfrared, public IGPS // 有红外、定位功能的T50
{
// ...
};
class T50AmphibianGPS : public T50, public Amphibian, public IGPS // 有两栖、定位功能的T50
{
// ...
};
class T50InfraredAmphibianGPS : public T50, public IInfrared, public IAmphibian, public IGPS // 有红外、两栖、定位功能的T50
{
// ...
};
一共有7个类。同样道理T75和T90也会各自派生出7个类,那么这样的派生的子类就会多达21个,以后每增加一个型号的坦克,都会增加类似的7个类。这种设计思路是静态的(即通过继承的方式来获得功能的扩充),即所有可能需要用到的类,必须在代码编译之前准备好,因此,上面的21个类我们都必须编写。
上面所描述的问题的根源在于我们“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质(即如前所言,必须在编译前将所有类的代码必须准备好),使得这种扩展方式缺乏灵活性;并且随着子类(各种不同型号的坦克)和扩展功能(红外、两栖和定位)的增多,各种子类和扩展功能的组合会导致子类的数量以几何级数的方式增长,以至于代码难以维护。
Decorator设计模式,就是使“对象功能的扩展”能够根据需要来动态地实现,同时可以避免“扩展功能的增多”导致子类数量急剧增多,从而使得任何“功能扩展变化”所产生的负面影响降为最低。
下面为Decorator的UML类图:
![11. C++实现Structural - Decorator模式 - 玄机逸士 - 玄机逸士博客](http://img.bimg.126.net/photo/CEbX-DWdoBThYDHhsY6iFQ==/2263903237685465037.jpg)
具体实现代码:
// Decorator.h
#include <string>
#include <iostream>
#include <memory>
using namespace std;
// 抽象类:Tank
class Tank
{
public:
virtual void shot() = 0;
virtual void run() = 0;
public:
virtual ~Tank()
{
cout << "in the destructor of Tank..." << endl;
}
};
// 具体坦克类:T50
class T50 : public Tank
{
public:
void shot()
{
cout << "Tank Type T50 : shot() : " << endl;
}
void run()
{
cout << "Tank Type T50 : run() : " << endl;
}
public:
virtual ~T50()
{
cout << "in the destructor of T50..." << endl;
}
};
// 具体坦克类:T75
class T75 : public Tank
{
public:
void shot()
{
cout << "Tank Type T75 : shot() : " << endl;
}
void run()
{
cout << "Tank Type T75 : run() : " << endl;
}
public:
virtual ~T75()
{
cout << "in the destructor of T75..." << endl;
}
};
// 具体坦克类:T90
class T90 : public Tank
{
public:
void shot()
{
cout << "Tank Type T90 : shot() : " << endl;
}
void run()
{
cout << "Tank Type T90 : run() : " << endl;
}
public:
virtual ~T90()
{
cout << "in the destructor of T90..." << endl;
}
};
//抽象类:Decorator
class Decorator : public Tank // "is - a"关系
{
protected:
auto_ptr<Tank> tank; // "has - a"关系
public:
Decorator(auto_ptr<Tank> tank) : tank(tank) // 具体的坦克类如T5或具体的装饰类
{ // 如InfraredDecorator均可作为参数
} // 传入
virtual ~Decorator()
{
cout << "in the destructor of Decorator..." << endl;
}
public:
void shot()
{
tank->shot();
}
void run()
{
tank->run();
}
};
class InfraredDecorator : public Decorator
{
private:
string infrared; // 这就是所谓的addedAtrribute
public:
InfraredDecorator(auto_ptr<Tank> tank) : Decorator(tank) // 调用Decorator类中的构造方法
{
}
virtual ~InfraredDecorator()
{
cout << "in the destructor of InfraredDecorator..." << endl;
}
public:
void set_Infrared(const string& infrared) // 这就所谓的addedOperation
{
this->infrared = infrared;
}
string get_Infrared() const
{
return infrared;
}
public:
void run()
{
tank->run();
// 下面的语句模拟增加红外功能。如果不想给run增加红外功能,则下面语句可以省去
set_Infrared("+ Infrared ");
cout << get_Infrared() << endl;
}
void shot()
{
tank->shot();
// 下面的语句模拟增加红外功能
set_Infrared("+ Infrared ");
cout << get_Infrared() << endl;
}
};
class AmphibianDecorator : public Decorator
{
private:
string amphibian; // 这就是所谓的addedAtrribute
public:
AmphibianDecorator(auto_ptr<Tank> tank) : Decorator(tank)
{
}
~AmphibianDecorator()
{
cout << "in the destructor of AmphibianDecorator..." << endl;
}
public:
void set_Amphibian(const string& amphibian) // 这就所谓的addedOperation
{
this->amphibian = amphibian;
}
string get_Amphibian() const
{
return amphibian;
}
public:
void run()
{
tank->run();
// 下面的语句模拟增加两栖功能
set_Amphibian("+ Amphibian ");
cout << get_Amphibian() << endl;
}
void shot()
{
tank->shot();
// 下面的语句模拟增加两栖功能
set_Amphibian("+ Amphibian ");
cout << get_Amphibian() << endl;
}
};
class GPSDecorator : public Decorator
{
private:
string gps; // 这就是所谓的addedAtrribute
public:
GPSDecorator(auto_ptr<Tank> tank) : Decorator(tank)
{
}
~GPSDecorator()
{
cout << "in the destructor of GPSDecorator..." << endl;
}
public:
void set_GPS(const string& gps) // 这就所谓的addedOperation
{
this->gps = gps;
}
string get_GPS() const
{
return gps;
}
public:
void run()
{
tank->run();
// 下面的语句模拟增加定位功能
set_GPS("+ GPS ");
cout << get_GPS() << endl;
}
void shot()
{
tank->shot();
// 下面的语句模拟增加定位功能
set_GPS("+ GPS ");
cout << get_GPS() << endl;
}
};
// Decorator.cpp
#include "Decorator.h"
int main(int argc, char **argv)
{
// 给T50增加红外功能
auto_ptr<Tank> tank1(new T50);
auto_ptr<Tank> pid1(new InfraredDecorator(tank1));
pid1->shot();
cout << endl;
pid1->run();
cout << "\n-------------------------------\n" << endl;
// 给T75增加红外、两栖功能
auto_ptr<Tank> tank2(new T75);
auto_ptr<Tank> pid2(new InfraredDecorator(tank2));
auto_ptr<Tank> pad2(new AmphibianDecorator(pid2));
pad2->shot();
cout << endl;
pad2->run();
cout << "\n-------------------------------\n" << endl;
// 给T75增加红外、两栖、定位功能
auto_ptr<Tank> tank3(new T90);
auto_ptr<Tank> pid3(new InfraredDecorator(tank3));
auto_ptr<Tank> pad3(new AmphibianDecorator(pid3));
auto_ptr<Tank> pgd3(new GPSDecorator(pad3));
pgd3->shot();
cout << endl;
pgd3->run();
cout << "\n-------------------------------\n" << endl;
}
运行结果:
Tank Type T50 : shot() :
+ Infrared
Tank Type T50 : run() :
+ Infrared
-------------------------------
Tank Type T75 : shot() :
+ Infrared
+ Amphibian
Tank Type T75 : run() :
+ Infrared
+ Amphibian
-------------------------------
Tank Type T90 : shot() :
+ Infrared
+ Amphibian
+ GPS
Tank Type T90 : run() :
+ Infrared
+ Amphibian
+ GPS
-------------------------------
in the destructor of GPSDecorator...
in the destructor of Decorator...
in the destructor of AmphibianDecorator...
in the destructor of Decorator...
in the destructor of InfraredDecorator...
in the destructor of Decorator...
in the destructor of T90...
in the destructor of Tank...
in the destructor of Tank...
in the destructor of Tank...
in the destructor of Tank...
in the destructor of AmphibianDecorator...
in the destructor of Decorator...
in the destructor of InfraredDecorator...
in the destructor of Decorator...
in the destructor of T75...
in the destructor of Tank...
in the destructor of Tank...
in the destructor of Tank...
in the destructor of InfraredDecorator...
in the destructor of Decorator...
in the destructor of T50...
in the destructor of Tank...
in the destructor of Tank...
Decorator设计模式要点:
- 通过采用组合,而非继承的手法,实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。
- Component类在Decorator设计模式中充当抽象接口的角色,不应该去实现具体的行为。而且Decorator类对于Component类应该透明,即Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。
- Decorator类在接口上表现为“is-a”Component的继承关系,即Decorator类继承了Component类所具有的接口;但在实现上又同时表现为“has-a”Component的组合关系,即Decorator类有使用了另外一个Component类。因此,我们可以使用一个或者多个Decorator对象来“装饰”一个Component对象,并且经过装饰后的对象仍然是一个Component对象。
- Decorator设计模式并非解决“多子类衍生的多继承”问题,但它事实上大幅度减少了子类的数量,如上例中21个子类全部可以无需存在(当然增加了一个Decorator抽象类)。不过,其应用的要点在于解决“主题类在多个方向上的扩展功能”,而这正是“装饰”的含义。
下面的UML类图,是在原图的基础上增加几个注解,用来说明上面的示例代码中的类和原图中的各类之间的对应关系,见带有颜色部分的注释。
Decorator模式可以被认为是Composite的简单版本,他们之间的不同是:
1. Composite中有多个Component对象,而Decorator中有且仅有一个Component对象;
2. Decorator用于增加函数的功能性,而Composite用于传递函数调用。