标签:中间 操作 动态 组合 修改 针对 需要 work 额外
动机:在软件设计过程中,如果责任划分不清楚,随着需求的变化,子类极具膨胀,同时充斥着相同的代码。这时候需要划清责任。
一个示例程序:
1 class Stream 2 { 3 public: 4 virtual void read() = 0; 5 virtual void write() = 0; 6 virtual ~Stream() {} 7 }; 8 class FileStream :public Stream 9 { 10 public: 11 virtual void read() 12 { 13 cout << "读文件流" << endl; 14 } 15 virtual void write() 16 { 17 cout << "写文件流" << endl; 18 } 19 }; 20 class NetworkStream :public Stream 21 { 22 public: 23 virtual void read() 24 { 25 cout << "读网络流" << endl; 26 } 27 virtual void write() 28 { 29 cout << "写网络流" << endl; 30 } 31 }; 32 class MemoryStream :public Stream 33 { 34 public: 35 virtual void read() 36 { 37 cout << "读内存流" << endl; 38 } 39 virtual void write() 40 { 41 cout << "写内存流" << endl; 42 } 43 }; 44 //加密文件流 45 class CryptoFileStream :public FileStream 46 { 47 public: 48 virtual void read() 49 { 50 FileStream::read(); 51 cout << "额外加密" << endl; 52 } 53 virtual void write() 54 { 55 FileStream::write(); 56 cout << "额外加密" << endl; 57 } 58 }; 59 //加密网络流 60 class CryptoNetworkStream :public NetworkStream 61 { 62 public: 63 64 virtual void read() 65 { 66 NetworkStream::read(); 67 cout << "额外加密" << endl; 68 } 69 virtual void write() 70 { 71 NetworkStream::write(); 72 cout << "额外加密" << endl; 73 } 74 }; 75 //加密内存流 76 class CryptoMemoryStream :public MemoryStream 77 { 78 public: 79 virtual void read() 80 { 81 MemoryStream::read(); 82 cout << "额外加密" << endl; 83 } 84 virtual void write() 85 { 86 MemoryStream::write(); 87 cout << "额外加密" << endl; 88 } 89 }; 90 //缓存文件流 91 class BufferFileStream :public FileStream 92 { 93 public: 94 virtual void read() 95 { 96 cout << "缓存操作" << endl; 97 FileStream::read(); 98 } 99 virtual void write() 100 { 101 cout << "缓存操作" << endl; 102 FileStream::write(); 103 } 104 }; 105 //缓存网络流 106 class BufferNetworkStream :public NetworkStream 107 { 108 public: 109 virtual void read() 110 { 111 cout << "缓存操作" << endl; 112 NetworkStream::read(); 113 } 114 virtual void write() 115 { 116 cout << "缓存操作" << endl; 117 NetworkStream::write(); 118 } 119 }; 120 //缓存内存流 121 class BufferMemoryFile :public MemoryStream 122 { 123 public: 124 virtual void read() 125 { 126 cout << "缓存操作" << endl; 127 MemoryStream::read(); 128 } 129 virtual void write() 130 { 131 cout << "缓存操作" << endl; 132 MemoryStream::write(); 133 } 134 };
仔细分析这个程序会发现:第51、67、82行的加密操作不会因为read的内容不同而不同,都是一样的加密操作。第56、72、87行针对写进行的加密操作也是一样的,这就出现了代码冗余。重复的代码太多,就需要消除重复。
第一步调整:将继承调整为组合。
1 //加密文件流 2 class CryptoFileStream 3 { 4 public: 5 virtual void read() 6 { 7 fstream->read(); 8 cout << "额外加密" << endl; 9 } 10 virtual void write() 11 { 12 fstream->read(); 13 cout << "额外加密" << endl; 14 } 15 private: 16 FileStream *fstream; 17 }; 18 //加密网络流 19 class CryptoNetworkStream 20 { 21 public: 22 23 virtual void read() 24 { 25 nstream->read(); 26 cout << "额外加密" << endl; 27 } 28 virtual void write() 29 { 30 nstream->write(); 31 cout << "额外加密" << endl; 32 } 33 private: 34 NetworkStream *nstream; 35 }; 36 //加密内存流 37 class CryptoMemoryStream 38 { 39 public: 40 virtual void read() 41 { 42 mstream-> read(); 43 cout << "额外加密" << endl; 44 } 45 virtual void write() 46 { 47 mstream->write(); 48 cout << "额外加密" << endl; 49 } 50 private: 51 MemoryStream *mstream; 52 };
第51、37、16行的变量定义都是某一个类的子类,这时可以提取公因式,把他们都声明成基类的类型。
class CryptoFileStream { public: virtual void read() { fstream->read(); cout << "额外加密" << endl; } virtual void write() { fstream->read(); cout << "额外加密" << endl; } private: Stream *fstream; // = new FileStream; 在未来运行时 }; //加密网络流 class CryptoNetworkStream { public: virtual void read() { nstream->read(); cout << "额外加密" << endl; } virtual void write() { nstream->write(); cout << "额外加密" << endl; } private: Stream *nstream; // = new networkStream; }; //加密内存流 class CryptoMemoryStream { public: virtual void read() { mstream-> read(); cout << "额外加密" << endl; } virtual void write() { mstream->write(); cout << "额外加密" << endl; } private: Stream *mstream; // = new memorystream };
代码层面发现这三个类一样,不一样的是在注释上,在运行时的未来不一样。总的来说在编译时一样,运行时不一样,这时设计模式的真谛。
将三类合一
// stream基类为cryptostream定义了接口规范 class CryptoStream :public Stream { public:
CryptoStream(Stream*s):stream(s){} virtual void read() { stream->read(); cout << "额外加密" << endl; } virtual void write() { stream->read(); cout << "额外加密" << endl; } private: Stream *stream; // = new FileStream....; 在未来运行时 //= new networkstream; // = new memorystream; };
编译运行
FileStream * fstream = new FileStream; CryptoStream *cs = new CryptoStream(fstream); cs->read(); cs->write(); NetworkStream *nstream = new NetworkStream; CryptoStream *cs2 = new CryptoStream(nstream); cs2->read(); cs2->write(); MemoryStream *mstream = new MemoryStream; CryptoStream *cs3 = new CryptoStream(mstream); cs3->read(); cs3->write();
将bufferStream也做相同的修改
1 class CryptoStream :public Stream 2 { 3 public: 4 CryptoStream(Stream *s) :stream(s){} 5 virtual void read() 6 { 7 stream->read(); 8 cout << "额外加密" << endl; 9 } 10 virtual void write() 11 { 12 stream->write(); 13 cout << "额外加密" << endl; 14 } 15 private: 16 Stream *stream; // = new FileStream....; 在未来运行时 17 }; 18 19 20 class BufferStream :public Stream 21 { 22 public: 23 BufferStream(Stream *s) :stream(s){} 24 virtual void read() 25 { 26 cout << "缓存操作" << endl; 27 stream->read(); 28 } 29 virtual void write() 30 { 31 cout << "缓存操作" << endl; 32 stream->write(); 33 } 34 private: 35 Stream *stream; //= new 36 };
第35、16行相同,将他们提取放在一个中间类中。
class Decorate :public Stream { public: Decorate(Stream *s) :stream(s){} protected: Stream *stream; }; //加密...流 class CryptoStream :public Decorate { public: CryptoStream(Stream *s) :Decorate(s){} virtual void read() { stream->read(); cout << "额外加密" << endl; } virtual void write() { stream->write(); cout << "额外加密" << endl; } }; class BufferStream :public Decorate { public: BufferStream(Stream *s) :Decorate(s){} virtual void read() { cout << "缓存操作" << endl; stream->read(); } virtual void write() { cout << "缓存操作" << endl; stream->write(); } };
全部修改完成之后,类与类之间的关系变成下面这样。
总结:
使用装饰模式的场景:在某些情况在,我会可能会过度的使用继承来扩展功能,由于继承为类型引入了静态特质(FileStream::read()),使其缺乏灵活性。随着功能的增多,会导致子类膨胀。
用组合来替换继承,运行时动态扩展功能,消除重复代码。Decorator类即继承了基类(is a),有内含有基类指针(has a)
装饰模式的结构:
标签:中间 操作 动态 组合 修改 针对 需要 work 额外
原文地址:https://www.cnblogs.com/xiaoxiaolinux/p/14458807.html