学习记录:《C++设计模式——李建忠主讲》4.“单一职责”模式

单一职责模式:在软件组件的设计中,若是责任划分的不清晰,使用继承获得的结果每每是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。缓存

典型模式:装饰模式(Decorator)、桥接模式(Bridge)。网络

1、装饰模式

1.动机

在某些状况下咱们可能会“过分地使用继承来扩展对象的功能”,因为继承为类型引入的静态特质,使得这种扩展方式缺少灵活性;而且随着子类的增多(扩展功能的增多),各类子类的组合(扩展功能的组合)会致使更多子类的膨胀。加密

2.做用

使“对象功能的扩展”可以根据须要来动态地实现;同时避免“扩展功能的增多”带来的子类膨胀问题,使得任何“功能扩展变化”所致使的影响降为最低。spa

3.定义

动态(组合)地给一个对象增长一些额外的职责。就增长功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码、减小子类个数)。设计

4.代码

//原有代码
//业务操做
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: //... }; class MemoryStream :public Stream{ public: //... }; //扩展操做 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: //... }; class CryptoMemoryStream : public MemoryStream{ public: //... }; //额外的缓冲操做... 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: //... }; class MemoryStream :public Stream{ public: //... }; //扩展操做 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); CryptoBufferedFileStream* s4=new BufferedStream(s2); }

 5.解析3d

       这是一个内容流程序,有读、定位(搜索)和写等功能,在业务上有文件流、网络流和内存流等,扩展出的功能包括额外加密操做和缓存操做等。指针

       在原有代码中,以继承的方法扩展这些功能,很详细也很好理解,但存在如下问题:继承引入了静态特质,使得这种扩展方式缺少灵活性;而且随着子类的增多(扩展功能的增多),各类子类的组合会致使更多子类的膨胀,以下图所示。假设一级功能有n种,二级功能有m种,则该程序一共有(1+n+X)个类。(思考X用n和m怎么表示)。code

       在运用装饰模式后的代码中,经过动态(组合)地给一个对象增长一些额外的职责,其结构如图所示,则该程序一共有(1+n+1+m)个类,相比以前大大减少了类的个数,且经过动态组合,将编译时依赖转化为运行时依赖。对象

6.结构

其中,Component(抽象类,如Stream):blog

      1.定义一个对象接口,能够给这些对象动态地添加职责。

ConcreteComponent(具体类,如FileStream、NetworkStream)

      1.定义一个对象,能够给这个对象添加一些职责

Decorator(装饰抽象类,如DecoratorStream)

      1.维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。

ConcreteDecorator(具体装饰类,如CryptoStream、BufferedStream)

      1.向组件添加职责

7.总结   

     1.经过采用组合而非继承的手法,Decorator模式实现了在运行时动态扩展对象功能的能力,并且能够根据须要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。

     2.Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具备的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另一个Component类。

     3.Decorator模式的目的并不是解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。

2、桥接模式

1.动机

因为某些类型固有的实现逻辑,使得它们具备两个变化的维度,乃至多个纬度的变化。

2.做用

使得该类型能够轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度,以应对这种“多维度的变化”。

3.定义

将抽象部分(业务功能)与实现部分(平台实现)分离,使它们均可以独立地变化。

4.代码

//原有代码
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(){} }; //平台实现 class PCMessagerBase : public Messager{ public: virtual void PlaySound(){ //**********  } virtual void DrawShape(){ //**********  } virtual void WriteText(){ //**********  } virtual void Connect(){ //**********  } }; class MobileMessagerBase : public Messager{ public: //********** }; //业务抽象 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: //********** }; class MobileMessagerPerfect : public MobileMessagerBase { public: //********** }; 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: //********** }; //业务抽象 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); }

 5.解析 

        这是一个关于在不一样平台(PC和Moblie)上,实现不一样业务(MessagerLite、MessagerPerfect)的程序。

        原有的代码与装饰模式中原有代码相似,经过不断地继承以扩展功能,但缺点也是显而易见的,容易形成子类的庞大不灵活。

        在运用桥接模式的代码中,将抽象部分(业务功能)与实现部分(平台实现)分离,使得抽象和实现能够沿着各自的维度来变化。

6.结构

 其中,     

       1.Abstraction:定义抽象类的接口;维护一个指向Implementtor类型对象的指针;

       2.RefinedAbstraction:扩充由Abstraction定义的接口;

       3.Implementor:定义实现类的接口,该接口不必定要与Abstraction的接口彻底一致,甚至能够彻底不一样;

       4.ConcreteImplementor:实现Implementor接口并定义它的具体实现。

7.总结

       1.Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现能够沿着各自的维度来变化。所谓抽象和实现沿着各自纬度的变化,即“子类化”它们。

       2.Bridge模式有时候相似于多继承方案,可是多继承方案每每违背单一职责原则(即一个类只有一个变化的缘由),复用性比较差。 Bridge模式是比多继承方案更好的解决方法。

       3.Bridge模式的应用通常在“两个很是强的变化维度”,有时一个类也有多于两个的变化维度,这时可使用Bridge的扩展模式。

相关文章
相关标签/搜索