单一职责模式
在软件组件的设计中,如果责任划分不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任 bad simie——代码大量重复
下面两种模式在责任划分方面尤为突出(其他的模式也是有职责划分问题的)
- 装饰模式Decorator
- 桥模式Bridge
1.装饰模式Decorator
动机: 在某些情况下过度的使用继承来扩展对象的功能,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多的子类膨胀
如何使对象功能的扩展能够依据需要来动态的实现同时避免扩展功能增多带来的子类膨胀问题?从而使得任何功能扩展变化所导致的影响降为最低?
//业务操作 流操作
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(byte 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(byte 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(byte data){
//额外的加密操作...
MemoryStream::Write(data);//写内存流
//额外的加密操作...
}
};
//流的缓冲
class BufferedFileStream : public FileStream{
//...
};
class BufferedNetworkStream : public NetworkStream{
//...
};
class BufferedMemoryStream : public MemoryStream{
//...
}
//流 加密+缓冲
class CryptoBufferedFileStream :public FileStream{
public:
virtual char Read(int number){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
//额外的缓冲操作...
}
virtual void Write(byte data){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Write(data);//写文件流
//额外的加密操作...
//额外的缓冲操作...
}
};
void Process(){
//编译时装配
CryptoFileStream *fs1 = new CryptoFileStream();
BufferedFileStream *fs2 = new BufferedFileStream();
CryptoBufferedFileStream *fs3 =new CryptoBufferedFileStream();
}
上述代码类关系图:
类太多了!!代码重复太多!!代码冗余
//修改过程
//业务操作 流操作
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{
//由继承改为组合
// //FileStream* 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(byte data){
// //额外的加密操作...
// stream->Write(data);//写文件流
// //额外的加密操作...
// }
// };
// class CryptoNetworkStream{
// Stream* stream;//=new NetWorkStream();
// public:
// virtual char Read(int number){
// //额外的加密操作...
// stream->Read(number);//读网络流
// }
// virtual void Seek(int position){
// //额外的加密操作...
// stream->Seek(position);//定位网络流
// //额外的加密操作...
// }
// virtual void Write(byte data){
// //额外的加密操作...
// stream->Write(data);//写网络流
// //额外的加密操作...
// }
// };
// class CryptoMemoryStream{
// Stream* stream;//=new MemoryStream();
// public:
// virtual char Read(int number){
// //额外的加密操作...
// stream->Read(number);//读内存流
// }
// virtual void Seek(int position){
// //额外的加密操作...
// stream->Seek(position);//定位内存流
// //额外的加密操作...
// }
// virtual void Write(byte data){
// //额外的加密操作...
// stream->Write(data);//写内存流
// //额外的加密操作...
// }
// };
//上面的加密操作都是一样的了 不一样的是注释的new ***Stream
//运行时让他们不一样 编译时是一样的
//编译时让他们复用 是一样的 运行时利用多态让他们不一样
//上述三个类就可以合并为一个类
class CryptoStream : public Stream{
Stream* stream;//=....
public:
CryptoStream(Stream *stream): stream(stream){}
//虚函数需要继承一个接口基类
virtual char Read(int number){
//额外的加密操作...
stream->Read(number);//读内存流
}
virtual void Seek(int position){
//额外的加密操作...
stream->Seek(position);//定位内存流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
stream->Write(data);//写内存流
//额外的加密操作...
}
};
//下面的操作同理
//流的缓冲
class BufferedFileStream : public FileStream{
//...
};
class BufferedNetworkStream : public NetworkStream{
//...
};
class BufferedMemoryStream : public MemoryStream{
//...
}
//流 加密+缓冲
class CryptoBufferedFileStream :public FileStream{
public:
virtual char Read(int number){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
//额外的缓冲操作...
}
virtual void Write(byte data){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Write(data);//写文件流
//额外的加密操作...
//额外的缓冲操作...
}
};
void Process(){
//编译时装配
CryptoFileStream *fs1 = new CryptoFileStream();
BufferedFileStream *fs2 = new BufferedFileStream();
CryptoBufferedFileStream *fs3 =new CryptoBufferedFileStream();
//更改后 运行时装配
FileStream* s1 = new FileStream();
CryptoStream* s2 = new CryptoStream(s1);//加密
BufferedStream* s3 = new BufferedStream(s1);//缓存
BufferedStream* s4 = new BufferedStream(s2);//加密 + 缓存
}
//修改后
//业务操作
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 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(byte data){
//额外的加密操作...
stream::Write(data);//写文件流
//额外的加密操作...
}
};
class BufferedStream : public Stream{
Stream* stream;//...
public:
BufferedStream(Stream* stm):stream(stm){
}
//...
};
void Process(){
//运行时装配
FileStream* s1=new FileStream();
CryptoStream* s2=new CryptoStream(s1);
BufferedStream* s3=new BufferedStream(s1);
BufferedStream* s4=new BufferedStream(s2);
}
//根据马丁弗勒经典重构
//如果某一个类它的多个子类有同样的字段 需要将字段往上提(提到基类或者中间类)
//stream提到基类Stream不合适 因为FileStream/NetworkStream等不需要stream这个字段 所以建立一个中间类比较合适
//业务操作
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){
//写内存流
}
};
//扩展操作
DecoratorStream: public Stream{
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(byte data){
//额外的加密操作...
stream::Write(data);//写文件流
//额外的加密操作...
}
};
class BufferedStream : public DecoratorStream{
Stream* stream;//...
public:
BufferedStream(Stream* stm):DecoratorStream(stm){
}
//...
};
void Process(){
//运行时装配
FileStream* s1=new FileStream();
CryptoStream* s2=new CryptoStream(s1);//加密
BufferedStream* s3=new BufferedStream(s1);//缓冲
BufferedStream* s4=new BufferedStream(s2);//加密+缓冲
}
上述代码类关系图:
- 继承->组合
- 编译时确定->运行时确定
- 当一个变量的声明类型都是某个类型的子类时 直接声明称父类类型就可以了
- 如果某一个类它的多个子类有同样的字段 需要将字段往上提(提到基类或者中间类)
模式定义: 动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码&减少子类个数)
要点总结:
- 通过采用组合而非继承的手法,Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的灵活性差和多子类衍生问题
- Decorator类在接口上表现为is-a component的继承关系,即Decorator类继承了component类所具有的接口。但在实现上又表现为has-a component的组合关系,即Decorator类又使用了另一个component类
- Decorator模式的目的并非解决多子类衍生的继承问题,Decorator模式应用的要点在于解决主体类在多个方向上的扩展功能——是为装饰的含义 filestream/networkstreaam等为主体的操作,而加密/缓冲等为扩展的操作
2.桥模式Bridge
动机: 由于某些类型的固有的实现逻辑,使得它们具有两个及以上变化的维度
如何应对这种多维度的变化?如何利用面向对象技术来使得类型可以轻松的沿着两个乃至多个方向变化而不引入额外的复杂度?
//通信工具在不同平台上的实现
class Messager{
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager(){}
};
//平台实现 pc和mobile n
class PCMessagerBase : public Messager{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerBase : public Messager{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象 精简版lite/完美版perfect m
//类的数目 1 + n + n * m
class PCMessagerLite : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::DrawShape();
//........
}
};
class PCMessagerPerfect : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::DrawShape();
//........
}
};
class MobileMessagerLite : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::DrawShape();
//........
}
};
class MobileMessagerPerfect : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::DrawShape();
//........
}
};
void Process(){
//编译时装配
Messager *m =
new MobileMessagerPerfect();
}
//修改流程
//实现通信
class Messager{
public:
//下面两波纯虚函数在其子类中只是部分override 将这两博东西放在一个类中不合适
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
// virtual void PlaySound()=0;
// virtual void DrawShape()=0;
// virtual void WriteText()=0;
// virtual void Connect()=0;
virtual ~Messager(){}
};
class MessagerImp{
public:
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~MessagerImp(){}
};
//平台实现 pc和mobile
class PCMessagerBase : public MessagerImp{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerBase : public MessagerImp{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象 精简版lite/完美版perfect
//下面这个精简版可以代替两个平台上的Lite版本
//perfect版本同理
class MessagerLite : public Messager{
MessagerImp* messagerimp;//=....运行时确定
//Messager* Messager;//= new PCMessagerBase(); 这行代码不成立 PCMessagerBase()是纯虚基类 只实现了部分纯虚函数
public:
virtual void Login(string username, string password){
messagerimp->Connect();
//........
}
virtual void SendMessage(string message){
messagerimp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerimp->DrawShape();
//........
}
};
class MessagerPerfect : public Messager{
MessagerImp* messagerimp;//...
public:
virtual void Login(string username, string password){
messagerimp->PlaySound();
//********
messagerimp->Connect();
//........
}
virtual void SendMessage(string message){
messagerimp->PlaySound();
//********
messagerimp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerimp->PlaySound();
//********
messagerimp->DrawShape();
//........
}
};
// class PCMessagerLite{
// Messager* messager;//= new PCMessagerBase();运行时确定
// public:
// virtual void Login(string username, string password){
// messager->Connect();
// //........
// }
// virtual void SendMessage(string message){
// messager->WriteText();
// //........
// }
// virtual void SendPicture(Image image){
// messager->DrawShape();
// //........
// }
// };
// class PCMessagerPerfect : public PCMessagerBase {
// public:
// virtual void Login(string username, string password){
// PCMessagerBase::PlaySound();
// //********
// PCMessagerBase::Connect();
// //........
// }
// virtual void SendMessage(string message){
// PCMessagerBase::PlaySound();
// //********
// PCMessagerBase::WriteText();
// //........
// }
// virtual void SendPicture(Image image){
// PCMessagerBase::PlaySound();
// //********
// PCMessagerBase::DrawShape();
// //........
// }
// };
// class MobileMessagerLite{
// MessagerBase* messager;//new mobileMessagerBase();
// public:
// virtual void Login(string username, string password){
// messager->Connect();
// //........
// }
// virtual void SendMessage(string message){
// messager->WriteText();
// //........
// }
// virtual void SendPicture(Image image){
// messager->DrawShape();
// //........
// }
// };
// class MobileMessagerPerfect : public MobileMessagerBase {
// public:
// virtual void Login(string username, string password){
// MobileMessagerBase::PlaySound();
// //********
// MobileMessagerBase::Connect();
// //........
// }
// virtual void SendMessage(string message){
// MobileMessagerBase::PlaySound();
// //********
// MobileMessagerBase::WriteText();
// //........
// }
// virtual void SendPicture(Image image){
// MobileMessagerBase::PlaySound();
// //********
// MobileMessagerBase::DrawShape();
// //........
// }
// };
void Process(){
//编译时装配
Messager *m =
new MobileMessagerPerfect();
}
//继承自同一基类的派生类有相同的字段 将字段向上提
//修改后
//一个类中放了不同的函数 不同的变化方向 一个是平台实现 一个是业务变化方向 不应该放在一个类中
class Messager{
protected:
MessagerImp* messagerImp;//...
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
class MessagerImp{
public:
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual MessagerImp(){}
};
//平台实现 n
class PCMessagerImp : public MessagerImp{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerImp : public MessagerImp{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象 m
//类的数目:1+n+m
class MessagerLite :public Messager {
public:
virtual void Login(string username, string password){
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->DrawShape();
//........
}
};
class MessagerPerfect :public Messager {
public:
virtual void Login(string username, string password){
messagerImp->PlaySound();
//********
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->PlaySound();
//********
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->PlaySound();
//********
messagerImp->DrawShape();
//........
}
};
void Process(){
//运行时装配
MessagerImp* mImp=new PCMessagerImp();
Messager *m =new Messager(mImp);
}
模式定义: 将抽象部分(业务功能)与实现部分(平台实现)分离,使他们都可以独立变化
- Abstraction——>Messager(里面有一个imp指针指向Implementor) 业务抽象
- Implementor——>MessagerImp 平台实现
- RefinedAbstraction——>Lite/Perfect
- ConcreteImplementor——>PC/Mobile
要点总结:
- Bridge模式使用对象间的组合关系解耦了抽象与实现之间的固有绑定关系, 使得抽象和实现可以沿着各自的维度变化。所谓抽象和实现沿着各自维度的变化,即子类化它们
- Bridge模式有时候类似于多继承方案 但多继承方案往往违背单一职责原则,复用性差。Bridge模式是比多继承方案更好的解决方法
- Bridge模式的应用一般在两个非常强的变化维度,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式 将不同的变化维度打包成不同的基类