“单一职责”模式:
在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结构往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。
典型模式
- Decorator
- Bridge
这两个模式在责任的变现上十分突出。
类的数量:1+n+n*m!/2
当一个变量的声明类型都是 某个类型的子类的时候,应该把它声明为某个类型
编译时让他们一样,运行时让他们不一样===》绝大多数设计模式的真谛
编译时让它共同复用它的变化,多态支持。
Stream* stream = new FileStream(); new NetworkStream(); new MemoryStream();
样子
//decorator1.cpp
//io流操作
//业务操作 基类
class Stream
{
public:
virtual char Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(char data) = 0;
virtual ~Stream() {}
};
//主体类 文件流
class FileStream : public Stream
{
public:
virtual char Read(int number)
{
//读文件流
}
virtual void Seek(int position)
{
//定位文件流
}
virtual void Write(char data)
{
//写文件流
}
};
//网络流
class NetworkStream :public Stream
{
public:
virtual char Read(int number)
{
//读网络流
}
virtual void Seek(int position)
{
//定位网络流
}
virtual void Write(char data)
{
//写网络流
}
};
//内存流
class MemoryStream :public Stream
{
public:
virtual char Read(int number)
{
//读内存流
}
virtual void Seek(int position)
{
//定位内存流
}
virtual void Write(char data)
{
//写内存流
}
};
//------------------------------------------
//扩展操作--对文件流加密
class CryptoFileStream :public FileStream
{
public:
virtual char Read(int number)
{
//额外的加密操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
FileStream::Seek(position);//读文件流
//额外的加密操作...
}
virtual void Write(char data)
{
//额外的加密操作...
FileStream::Write(data);//读文件流
//额外的加密操作...
}
};
//对网络流加密
class CryptoNetworkStream :public NetworkStream
{
public:
virtual char Read(int number)
{
//额外的加密操作...
NetworkStream::Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
NetworkStream::Seek(position);//读文件流
//额外的加密操作...
}
virtual void Write(char data)
{
//额外的加密操作...
NetworkStream::Write(data);//读文件流
//额外的加密操作...
}
};
//对内存流加密
class CryptoMemoryStream :public MemoryStream
{
public:
virtual char Read(int number)
{
//额外的加密操作...
MemoryStream::Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
MemoryStream::Seek(position);//读文件流
//额外的加密操作...
}
virtual void Write(char data)
{
//额外的加密操作...
MemoryStream::Write(data);//读文件流
//额外的加密操作...
}
};
//-----------------------------------------------------------
//缓冲
class BufferedFileStream :public FileStream
{
//...
};
class BufferedNetworkStream :public NetworkStream
{
//...
};
class BufferedMemoryStream :public MemoryStream
{
//..
};
//对缓冲加密
class CryBufferedFileStream :public FileStream
{
public:
virtual char Read(int number)
{
//额外的加密操作...
//额外的缓冲操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
//额外的缓冲操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
//额外的缓冲操作...
}
};
//decorator2.cpp GeekBand
//io流操作 本文件对上一个文件进行修改
//业务操作 基类
class Stream
{
public:
virtual char Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(char data) = 0;
virtual ~Stream() {}
};
//主体类 文件流
class FileStream : public Stream
{
public:
virtual char Read(int number)
{
//读文件流
}
virtual void Seek(int position)
{
//定位文件流
}
virtual void Write(char data)
{
//写文件流
}
};
//网络流
class NetworkStream :public Stream
{
public:
virtual char Read(int number)
{
//读网络流
}
virtual void Seek(int position)
{
//定位网络流
}
virtual void Write(char data)
{
//写网络流
}
};
//内存流
class MemoryStream :public Stream
{
public:
virtual char Read(int number)
{
//读内存流
}
virtual void Seek(int position)
{
//定位内存流
}
virtual void Write(char data)
{
//写内存流
}
};
//先把继承用组合替换。组合优于继承
//当一个变量的声明类型都是 某个类型的子类的时候,应该把它声明为某个类型
//------------------------------------------
//扩展操作--对文件流加密
class CryptoFileStream :public Stream//还是要加上基类,为保证虚函数的接口规范
{
//先把继承用组合替换。组合优于继承
//当一个变量的声明类型都是 某个类型的子类的时候,应该把它声明为某个类型
Stream* stream;//=new FileStream();
public:
virtual char Read(int number)
{
//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
stream->Seek(position);//读文件流
//额外的加密操作...
}
virtual void Write(char data)
{
//额外的加密操作...
stream->Write(data);//读文件流
//额外的加密操作...
}
};
//对网络流加密
class CryptoNetworkStream :public Stream//还是要加上基类,为保证虚函数的接口规范
{
Stream* stream; //=new NetworkStream();
public:
virtual char Read(int number)
{
//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
stream->Seek(position);//读文件流
//额外的加密操作...
}
virtual void Write(char data)
{
//额外的加密操作...
stream->:Write(data);//读文件流
//额外的加密操作...
}
};
//对内存流加密
class CryptoMemoryStream :public Stream//还是要加上基类,为保证虚函数的接口规范
{
Stream* stream;// = new MemoryStream();
public:
virtual char Read(int number)
{
//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
stream->Seek(position);//读文件流
//额外的加密操作...
}
virtual void Write(char data)
{
//额外的加密操作...
stream->Write(data);//读文件流
//额外的加密操作...
}
};
/*
*这样做了以后发现这三个类只有类名不一样,其余都一样===》合并,用一个类就可以了
* 这个地方既有Stream基类,也有Stream成员变量
*/
class CryptoStream :public Stream//还是要加上基类,为保证虚函数的接口规范
{
//先把继承用组合替换。组合优于继承
//当一个变量的声明类型都是 某个类型的子类的时候,应该把它声明为某个类型
Stream* stream;//。。。
public:
CryptoStream(Stream* stm) :
stream(stm)
{
}
virtual char Read(int number)
{
//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
stream->Seek(position);//读文件流
//额外的加密操作...
}
virtual void Write(char data)
{
//额外的加密操作...
stream->Write(data);//读文件流
//额外的加密操作...
}
};
//-----------------------------------------------------------
//~~~~~~~~~~~~~~~~~
//缓冲
class BufferedFileStream :public FileStream
{
//...
};
class BufferedNetworkStream :public NetworkStream
{
//...
};
class BufferedMemoryStream :public MemoryStream
{
//..
};
//同样,buffer也可以这样
//缓冲
class BufferedStream :public Stream
{
Stream* stream;
//...
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//对缓冲加密
class CrytoBufferedFileStream :public FileStream
{
public:
virtual char Read(int number)
{
//额外的加密操作...
//额外的缓冲操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
//额外的缓冲操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
//额外的缓冲操作...
}
};
void Process()
{
//编译时装配
CryptoFileStream* fs1 = new CryptoFileStream();
BufferedFileStream* fs2 = new BufferedFileStream();
CrytoBufferedFileStream* fs3 = new CrytoBufferedFileStream();
}
void Process_2()
{
//运行时装配 ====替换上面
FileStream* s1 = new FileStream();
CryptoStream* s2 = new CryptoStream(s1);
BufferedStream* s3 = new BufferedStream(s1);
BufferedStream* s4 = new BufferedStream(s2);
}
//decorator3.cpp GeekBand
//io流操作 本文件对上一个文件进行修改
//业务操作 基类
class Stream
{
public:
virtual char Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(char data) = 0;
virtual ~Stream() {}
};
//主体类 文件流
class FileStream : public Stream
{
public:
virtual char Read(int number)
{
//读文件流
}
virtual void Seek(int position)
{
//定位文件流
}
virtual void Write(char data)
{
//写文件流
}
};
//网络流
class NetworkStream :public Stream
{
public:
virtual char Read(int number)
{
//读网络流
}
virtual void Seek(int position)
{
//定位网络流
}
virtual void Write(char data)
{
//写网络流
}
};
//内存流
class MemoryStream :public Stream
{
public:
virtual char Read(int number)
{
//读内存流
}
virtual void Seek(int position)
{
//定位内存流
}
virtual void Write(char data)
{
//写内存流
}
};
//装饰类就是把这个Stream往上提
//扩展操作,就是在谁的基础上操作就是装饰。附着在其他地方。
class DecoratorStream :public Stream
{
protected://从子类提取上来的,给子类用的,所以是protected
Stream* stream;//。。。这个是设计的核心,用组合的方式引出一种多态的支持未来的变化
DecoratorStream(Stream* stm)
:stream(stm)
{
}
};
class CryptoStream :public DecoratorStream
{
public:
CryptoStream(Stream* stm) :
DecoratorStream(stm)
{
}
virtual char Read(int number)
{
//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
stream->Seek(position);//读文件流
//额外的加密操作...
}
virtual void Write(char data)
{
//额外的加密操作...
stream->Write(data);//读文件流
//额外的加密操作...
}
};
//-----------------------------------------------------------
//~~~~~~~~~~~~~~~~~
//缓冲
//同样,buffer也可以这样
//缓冲
class BufferedStream :public DecoratorStream
{
public:
BufferedStream(Stream* stm)
:DecoratorStream(stm)
{
}
//...
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//对缓冲加密
class CrytoBufferedFileStream :public FileStream
{
public:
virtual char Read(int number)
{
//额外的加密操作...
//额外的缓冲操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position)
{
//额外的加密操作...
//额外的缓冲操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
//额外的缓冲操作...
}
};
void Process()
{
//编译时装配
CryptoFileStream* fs1 = new CryptoFileStream();
BufferedFileStream* fs2 = new BufferedFileStream();
CrytoBufferedFileStream* fs3 = new CrytoBufferedFileStream();
}
void Process_2()
{
//运行时装配 ====替换上面
FileStream* s1 = new FileStream();
CryptoStream* s2 = new CryptoStream(s1);
BufferedStream* s3 = new BufferedStream(s1);
BufferedStream* s4 = new BufferedStream(s2);
}
n+m个类
类的数量:1+n+1+m
对继承的不良使用。
组合更好使用
//扩展操作,就是在谁的基础上操作就是装饰。附着在其他地方。
class DecoratorStream :public Stream
{
protected://从子类提取上来的,给子类用的,所以是protected
Stream* stream;//。。。这个是设计的核心,用组合的方式引出一种多态的支持未来的变化
DecoratorStream(Stream* stm)
:stream(stm)
{
}
};
动机(Motivation)
在某些清空下,我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。
如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?
静态特质:
FileStream::Read(number);//读文件流
NetworkStream::Read(number);//读文件流
MemoryStream::Read(number);//读文件流
//多态指针调用
//动态特质 组合实现的
stream->Read(number);//读文件流
模式定义
动态(组合)地给一个对象增加一些额外地职责。就增加功能而言,Decorator模式比子类(继承)更为灵活(消除复用代码&减少子类个数)。
----《设计模式》 GoF
要点总结
- 通过采用组合而非继承地手法,Decorator模式实现了在运行时动态扩展对象功能地能力,而且可以根据需要扩展多个功能。避免了使用继承带来地“灵活性差”和“多子类衍生问题”。
- Decorator类在接口上表现为 is-a Component 的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。
- Decorator模式的目的并非解决“多子类衍生的多继承”问题。Decorator模式应用的要点在于解决“主体类”在多个方向上的扩展功能----是为“装饰”的含义。
既继承、又组合 表现为has-a.。
Decorator特点:
一个类中 父类是Stream, 类成员中含有Stream 对象。就要高度怀疑(99%)是Decorator模式
因为正常情况下不会这么干,要么继承要么组合,这么做肯定又独特的设计。
父类与构造器参数是同一类型===》Decorator模式
class DecoratorStream:public Stream
{
protected:
Stream *stream;
DecoratorStream(Stream* stm):stream(stm)
{}
};
主题操作,扩展操作。
捶胸顿足的感觉啊。。GoF大师就是大师。妞