• 设计模式


    “单一职责”模式

    在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。 

    典型模式
    Decorator
    Bridge

    代码示例:

      1 //业务操作
      2 class Stream{
      3 public  4     virtual char Read(int number)=0;
      5     virtual void Seek(int position)=0;
      6     virtual void Write(char data)=0;
      7     
      8     virtual ~Stream(){}
      9 };
     10 
     11 //主体类
     12 class FileStream: public Stream{
     13 public:
     14     virtual char Read(int number){
     15         //读文件流
     16     }
     17     virtual void Seek(int position){
     18         //定位文件流
     19     }
     20     virtual void Write(char data){
     21         //写文件流
     22     }
     23 
     24 };
     25 
     26 class NetworkStream :public Stream{
     27 public:
     28     virtual char Read(int number){
     29         //读网络流
     30     }
     31     virtual void Seek(int position){
     32         //定位网络流
     33     }
     34     virtual void Write(char data){
     35         //写网络流
     36     }
     37     
     38 };
     39 
     40 class MemoryStream :public Stream{
     41 public:
     42     virtual char Read(int number){
     43         //读内存流
     44     }
     45     virtual void Seek(int position){
     46         //定位内存流
     47     }
     48     virtual void Write(char data){
     49         //写内存流
     50     }
     51     
     52 };
     53 
     54 //扩展操作
     55 class CryptoFileStream :public FileStream{
     56 public:
     57     virtual char Read(int number){
     58        
     59         //额外的加密操作...
     60         FileStream::Read(number);//读文件流
     61         
     62     }
     63     virtual void Seek(int position){
     64         //额外的加密操作...
     65         FileStream::Seek(position);//定位文件流
     66         //额外的加密操作...
     67     }
     68     virtual void Write(byte data){
     69         //额外的加密操作...
     70         FileStream::Write(data);//写文件流
     71         //额外的加密操作...
     72     }
     73 };
     74 
     75 class CryptoNetworkStream : :public NetworkStream{
     76 public:
     77     virtual char Read(int number){
     78         
     79         //额外的加密操作...
     80         NetworkStream::Read(number);//读网络流
     81     }
     82     virtual void Seek(int position){
     83         //额外的加密操作...
     84         NetworkStream::Seek(position);//定位网络流
     85         //额外的加密操作...
     86     }
     87     virtual void Write(byte data){
     88         //额外的加密操作...
     89         NetworkStream::Write(data);//写网络流
     90         //额外的加密操作...
     91     }
     92 };
     93 
     94 class CryptoMemoryStream : public MemoryStream{
     95 public:
     96     virtual char Read(int number){
     97         
     98         //额外的加密操作...
     99         MemoryStream::Read(number);//读内存流
    100     }
    101     virtual void Seek(int position){
    102         //额外的加密操作...
    103         MemoryStream::Seek(position);//定位内存流
    104         //额外的加密操作...
    105     }
    106     virtual void Write(byte data){
    107         //额外的加密操作...
    108         MemoryStream::Write(data);//写内存流
    109         //额外的加密操作...
    110     }
    111 };
    112 
    113 class BufferedFileStream : public FileStream{
    114     //...
    115 };
    116 
    117 class BufferedNetworkStream : public NetworkStream{
    118     //...
    119 };
    120 
    121 class BufferedMemoryStream : public MemoryStream{
    122     //...
    123 }
    124 
    125 
    126 
    127 
    128 class CryptoBufferedFileStream :public FileStream{
    129 public:
    130     virtual char Read(int number){
    131         
    132         //额外的加密操作...
    133         //额外的缓冲操作...
    134         FileStream::Read(number);//读文件流
    135     }
    136     virtual void Seek(int position){
    137         //额外的加密操作...
    138         //额外的缓冲操作...
    139         FileStream::Seek(position);//定位文件流
    140         //额外的加密操作...
    141         //额外的缓冲操作...
    142     }
    143     virtual void Write(byte data){
    144         //额外的加密操作...
    145         //额外的缓冲操作...
    146         FileStream::Write(data);//写文件流
    147         //额外的加密操作...
    148         //额外的缓冲操作...
    149     }
    150 };
    151 
    152 
    153 
    154 void Process(){
    155 
    156         //编译时装配
    157     CryptoFileStream *fs1 = new CryptoFileStream();
    158 
    159     BufferedFileStream *fs2 = new BufferedFileStream();
    160 
    161     CryptoBufferedFileStream *fs3 =new CryptoBufferedFileStream();
    162 
    163 }
    decorator1.cpp

    流stream作为一个基类有一些基础的方法,如read,write,seek

    各种流文件流,网络流,内存流等继承于基类流,同时会有扩展的需求,如加密,且加密相同,只是读取的操作不一样,因此又会有新的不同流的扩展类继承于各种流。当然除了加密还会有其他的扩展操作如缓冲buffer,同理也可以像加密一样继承。

    如果要对一种流既加密又缓冲,可以继承了流之后在读写方法中添加加密操作,缓冲,读流的基础操作。

    以上的代码会有什么缺陷?

     

     随着扩展方法的增加,由于对继承的不良使用,子类的规模不断膨胀,产生很多重复的代码。

    改进一:使用组合

      1 //业务操作
      2 class Stream{
      3 
      4 public  5     virtual char Read(int number)=0;
      6     virtual void Seek(int position)=0;
      7     virtual void Write(char data)=0;
      8     
      9     virtual ~Stream(){}
     10 };
     11 
     12 //主体类
     13 class FileStream: public Stream{
     14 public:
     15     virtual char Read(int number){
     16         //读文件流
     17     }
     18     virtual void Seek(int position){
     19         //定位文件流
     20     }
     21     virtual void Write(char data){
     22         //写文件流
     23     }
     24 
     25 };
     26 
     27 class NetworkStream :public Stream{
     28 public:
     29     virtual char Read(int number){
     30         //读网络流
     31     }
     32     virtual void Seek(int position){
     33         //定位网络流
     34     }
     35     virtual void Write(char data){
     36         //写网络流
     37     }
     38     
     39 };
     40 
     41 class MemoryStream :public Stream{
     42 public:
     43     virtual char Read(int number){
     44         //读内存流
     45     }
     46     virtual void Seek(int position){
     47         //定位内存流
     48     }
     49     virtual void Write(char data){
     50         //写内存流
     51     }
     52     
     53 };
     54 
     55 //扩展操作
     56 class CryptoStream: public Stream {
     57     
     58     Stream* stream;//...
     59 
     60 public:
     61     CryptoStream(Stream* stm):stream(stm){
     62     
     63     }
     64     
     65     
     66     virtual char Read(int number){
     67        
     68         //额外的加密操作...
     69         stream->Read(number);//读文件流
     70     }
     71     virtual void Seek(int position){
     72         //额外的加密操作...
     73         stream::Seek(position);//定位文件流
     74         //额外的加密操作...
     75     }
     76     virtual void Write(byte data){
     77         //额外的加密操作...
     78         stream::Write(data);//写文件流
     79         //额外的加密操作...
     80     }
     81 };
     82 
     83 
     84 
     85 class BufferedStream : public Stream{
     86     
     87     Stream* stream;//...
     88     
     89 public:
     90     BufferedStream(Stream* stm):stream(stm){
     91         
     92     }
     93     //...
     94 };
     95 
     96 
     97 void Process(){
     98 
     99     //运行时装配
    100     FileStream* s1=new FileStream();
    101     CryptoStream* s2=new CryptoStream(s1);
    102     
    103     BufferedStream* s3=new BufferedStream(s1);
    104     
    105     BufferedStream* s4=new BufferedStream(s2);
    106     
    107     
    108 
    109 }
    decorator2.cpp

    若多个子类含有相同的字段,那应该将该字段向上层提。

    改进二:于是在创建一个中间类Decorator

      1 //业务操作
      2 class Stream{
      3 
      4 public  5     virtual char Read(int number)=0;
      6     virtual void Seek(int position)=0;
      7     virtual void Write(char data)=0;
      8     
      9     virtual ~Stream(){}
     10 };
     11 
     12 //主体类
     13 class FileStream: public Stream{
     14 public:
     15     virtual char Read(int number){
     16         //读文件流
     17     }
     18     virtual void Seek(int position){
     19         //定位文件流
     20     }
     21     virtual void Write(char data){
     22         //写文件流
     23     }
     24 
     25 };
     26 
     27 class NetworkStream :public Stream{
     28 public:
     29     virtual char Read(int number){
     30         //读网络流
     31     }
     32     virtual void Seek(int position){
     33         //定位网络流
     34     }
     35     virtual void Write(char data){
     36         //写网络流
     37     }
     38     
     39 };
     40 
     41 class MemoryStream :public Stream{
     42 public:
     43     virtual char Read(int number){
     44         //读内存流
     45     }
     46     virtual void Seek(int position){
     47         //定位内存流
     48     }
     49     virtual void Write(char data){
     50         //写内存流
     51     }
     52     
     53 };
     54 
     55 //扩展操作
     56 
     57 DecoratorStream: public Stream{
     58 protected:
     59     Stream* stream;//...
     60     
     61     DecoratorStream(Stream * stm):stream(stm){
     62     
     63     }
     64     
     65 };
     66 
     67 class CryptoStream: public DecoratorStream {
     68  
     69 
     70 public:
     71     CryptoStream(Stream* stm):DecoratorStream(stm){
     72     
     73     }
     74     
     75     
     76     virtual char Read(int number){
     77        
     78         //额外的加密操作...
     79         stream->Read(number);//读文件流
     80     }
     81     virtual void Seek(int position){
     82         //额外的加密操作...
     83         stream::Seek(position);//定位文件流
     84         //额外的加密操作...
     85     }
     86     virtual void Write(byte data){
     87         //额外的加密操作...
     88         stream::Write(data);//写文件流
     89         //额外的加密操作...
     90     }
     91 };
     92 
     93 
     94 
     95 class BufferedStream : public DecoratorStream{
     96     
     97     Stream* stream;//...
     98     
     99 public:
    100     BufferedStream(Stream* stm):DecoratorStream(stm){
    101         
    102     }
    103     //...
    104 };
    105 
    106 void Process(){
    107 
    108     //运行时装配
    109     FileStream* s1=new FileStream();
    110     
    111     CryptoStream* s2=new CryptoStream(s1);
    112     
    113     BufferedStream* s3=new BufferedStream(s1);
    114     
    115     BufferedStream* s4=new BufferedStream(s2);
    116     
    117     
    118 
    119 }
    decorator3.cpp

     在DecoratorStream中,使用组合的方式实现多态,包含了Stream基类。

    装饰模式,动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更灵活。有时我们希望给某个对象而不是整个类添加一些功能。例如上面的例子,有一个文件流,允许对它添加加密或者缓冲的扩展功能。装饰模式下,会将文件流嵌入到另一个对象(Decorator)中,由该对象完成特性的添加,该嵌入的对象就成为装饰,这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。

    动机

    • 在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。
    • 如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响将为最低?

    继承引入的静态特性如下第七行:

     1 //扩展操作
     2 class CryptoFileStream :public FileStream{
     3 public:
     4     virtual char Read(int number){
     5        
     6         //额外的加密操作...
     7         FileStream::Read(number);//读文件流
     8     }
     9     ...
    10 }

    组合引入的动态特性如下第八行:

     1 class CryptoStream: public DecoratorStream {
     2 
     3 public:
     4     CryptoStream(Stream* stm):DecoratorStream(stm){
     5     
     6     }
     7     
     8     virtual char Read(int number){
     9         //额外的加密操作...
    10         stream->Read(number);//读文件流
    11     }
    12     ...
    13 }

    模式定义

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

                                  ——《设计模式》GoF

    要点总结

    • 通过采用组合而非继承的手法, Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题” 
    • Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类 
    • Decorator模式的目的并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义 

    (若一个类继承了一个父类,且在字段里包含(组合)了该父类,很大可能就是Decorator设计模式,基类和组合在功能上由类似的地方,一般来说不会在一个类中同时继承和组合同一个类。但在装饰模式中,使用继承是为了完善基类stream接口的规范,使用组合是为了支持调用filestream,netstream中的接口)     

    装饰模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。装饰模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用装饰类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能

     参考:

    设计模式C++实现(11)——装饰模式

    Decorator

  • 相关阅读:
    Apache 2.4+php 5.4 安装
    Linux 进程状态
    解决Redhat Linux AS使用yum时出现This system is not registered with RHN的问题(改用CentOS的yum)
    nagios 事件处理
    awk调用shell命令的两种方法:system与print
    磁盘性能分析
    如何通过JQuery将DIV的滚动条滚动到指定的位置
    GCC Windows Linux 下编译学习1
    Linux命令
    GCC Windows Linux 下编译学习2
  • 原文地址:https://www.cnblogs.com/y4247464/p/14259058.html
Copyright © 2020-2023  润新知