装饰模式,又称包装器(wrapper),该模式的使用场景是,动态的给对象扩展一些额外的职责。职责即功能,所谓“动态”表示可以任意搭配我想要的功能,功能调用的先后顺序也可以任意设置。
用组合的方式来代替继承的方式,避免子类膨胀和继承的滥用,使“对象功能扩展”能够根据需要来动态的扩展实现。例如在抽象类Stream中,派生了 文件流,网络流,内存流,等如果要在着三个流上添加流的加密,流的缓存,流的加密和缓存功能,可以比较方法1继承的实现方式和方法2组合的形式。
class Stream{
public:
virtual char read(int num) = 0;
virtual void seek(int num) = 0;
virtual void write(int num) = 0;
};
//文件流
class FileStream:Stream{
public :
virtual char read(int num) {
// 读文件的功能
//fileread();
}
virtual void seek(int num){
// 查询文件功能
//fileseek();
}
virtual void write(int num) {
//写文件功能
//fileWrite()
}
};
//内存流
class MemoryStream:Stream{
public :
virtual char read(int num) {
// 读内存的功能
//memoryread();
}
virtual void seek(int num){
// 查询内存功能
//memoryseek();
}
virtual void write(int num) {
//写内存功能
//memoryWrite()
}
};
//加密文件流类
class CryptoFileStream : public FileStream{
virtual char read(int num) {
// 加密内容
// crypto();
// 读文件的功能
//fileread();
}
virtual void seek(int num){
// 加密内容
// crypto();
// 查询文件功能
//fileseek();
// 解密内容
// decrypto();
}
virtual void write(int num) {
// 加密内容
// crypto();
//写文件功能
//fileWrite()
}
};
//加密内存流
class CryptoMemoryStream: public:MemoryStream{
public :
virtual char read(int num) {
// 加密内容
// crypto();
// 读内存的功能
//memoryread();
}
virtual void seek(int num){
// 加密内容
// crypto();
// 查询内存功能
//memoryseek();
// 解密内容
// decrypto();
}
virtual void write(int num) {
// 加密内容
// crypto();
//写内存功能
//memoryWrite()
}
};
第一种方法实际上就是滥用继承的例子:假如现有一个需求“需要给文件流网络流新增一个缓存的功能”,按照第一种的设计方式是不是要在派生出 ”缓存文件流类“,”缓存网络流类“呢?假如需要再新增一个网络流,按照第一种方法是不是要新增一个继承Stream 的网络流类,再派生出 “加密网络流类”,"缓存网络流类" 呢? 实际上,第一种的设计存在很大的代码冗余,文件流,内存流,网络流等实体类在加密时的过是一样的,即“稳定”,唯一变化的实际上是读查写操作。文件流和加密文件流之间的关系实际上并不应是“父子关系”,继承的正确使用场景应是业务理论上面的细化,例如平行四边形和矩形的关系,矩形和正方形的关系,而功能上的扩展不应该用继承,而应该用组合,例如“正方形 与 涂上颜色的正方形之间的关系”就不该用继承。
装饰模式实际上就是组合
class Stream{
public:
virtual char read(int num) = 0;
virtual void seek(int num) = 0;
virtual void write(int num) = 0;
};
//文件流
class FileStream:Stream{
public :
virtual char read(int num) {
// 读文件的功能
//fileread();
}
virtual void seek(int num){
// 查询文件功能
//fileseek();
}
virtual void write(int num) {
//写文件功能
//fileWrite()
}
};
//内存流
class MemoryStream:Stream{
public :
virtual char read(int num) {
// 读内存的功能
//memoryread();
}
virtual void seek(int num){
// 查询内存功能
//memoryseek();
}
virtual void write(int num) {
//写内存功能
//memoryWrite()
}
};
//功能装饰流类
class DecoratorStream : public Stream{
protected:
Stream * stream;
public:
DecoratorStream(Stream * s ):stream(s){}
};
//流加密
class CryptoStream: public DecoratorStream {
public :
CryptoStream( Stream *s):DecoratorStream (s){}
virtual char read(int num) {
// 加密内容
// crypto();
stream ->read();
}
virtual void seek(int num){
// 加密内容
// crypto();
// 查询
stream ->seek();
// 解密内容
// decrypto();
}
virtual void write(int num) {
// 加密内容
// crypto();
//写功能
stream ->Write()
}
};
//流缓存
class BufferStream: public DecoratorStream {
public :
BufferStream( Stream *s):DecoratorStream (s){}
virtual char read(int num) {
//读缓存
if(bufferread() == null){
stream ->read();
//写缓存内容
bufferwrite();
}
}
virtual void seek(int num){
//读缓存
if(bufferread() == null){
stream ->seek();
//写缓存内容
bufferwrite();
}
}
virtual void write(int num) {
//写功能
stream ->Write()
bufferwrite();
}
};
///
void main(){
Stream* fstream = new FileStream();
fstream->write() ; //写文件
Stream * cryptofstream = new CryptoStream(fstream) ;
cryptofstream ->write() ; // 加密写文件
Stream * buffercryptofstream = new BufferStream(cryptofstream) ;
buffercryptofstream ->write () ; //先缓存后加密写文件
}
上述就是装饰模式,如果 DecoratorStream 类没有继承Stream ,那么就不支持先缓存后加密写文件的功能,继承了Stream就表示装配了该功能后还是个stream对象。DecoratorStream类中没有Stream * stream; 成员指针,那么就没法进行功能上的装饰,和方法1比起来,大大简化了代码,摆脱了继承的滥用。增强了可维护性,将来如果“细化5个流的实体类和5个流的功能”方法1需要新增的类的数量就是巨大的,而方法而只需要新增10个就可在实现流功能的任意搭配。