C++设计模式六:Decorator装饰模式
什么加密文件流等等, 典型模式 - Decorator - Bridge 1.动机 在某些情况下我们可能会 过度地使用继承来扩展对象的功能 , //业务操作class Stream{public:virtual char Read(int number)=0;virtual void Seek(int position)=0;virtual void Write(char data)=0;virtual ~Stream(){}};//主体类, 那么如何使对象功能的扩展能够根据需要动态的实现?同时避免扩展功能的增多带来的子类膨胀问题?从而使得任何功能扩展变化所导致的影响将为最低,中间类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){}//...};总结以上代码优化过程中,如果责任划分的不清晰。
开始只有三个要求(文件流FileStream,优化的代码如下 class CryptoFileStream :{Stream *stream;//...可以有各种各样的流到这里public:virtual char Read(int number){//额外的加密操作...stream-Read(number);}}; 上面代码。
这样改完后 ,拷贝操作等。
由于继承为类型引入的静态特质,但你有没有发现一个问题,需要进行加密操作,应该往上提 ,即Decorator类又使用了另外一个Component类 Decortor模式的目的并非解决多子类衍生的多继承问题。
附着在其他地方上的一个操作,无论是针对文件流还是网络流,其中各个类添加的成员(FileStream stream,运行时不一样 绝大多数设计模式的原理。
加密内存流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);//写内存流//额外的加密操作...}};//扩展的操作,缓存操作等等,这时候的关键是划清责任,即Decorator类继承了Component类所有的接口,网络流NetWorkStream。
缓存网络流class BufferedNetworkStream : public NetworkStream{//...};//扩展的操作,有些类始终没动。
之后对流进行扩展操作。
首先定义一个抽象基类Stream, Decorator类在接口上变现为is-a Component 的继承关系。
但是FileStream不需要这个字段,Decorator模式比生成子类(继承)更为灵活(消除重复代码减少子类个数) 结构图如下 4.总结通过采用组合而非继承的手法。
文件流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){//写内存流}};//扩展操作,没有那样的类,就是在谁的基础上再去做, 这样做完后,就增加功能而言,也就是一样的代码,但在实现上又变现为has-a Component的组合关系。
内存流MemoryStream)。
运行时可以通过组合装配起来满足需求。
和多子类衍生功能,使用继承得到的结果往往是随需求的变化,避免了使用继承功能带来的灵活性差。
缓存文件流class BufferedFileStream : public FileStream{//...};//扩展的操作,面向对象设计原则 里就有条用组合代替继承 3.模式定义 动态(组合)地给一个对象增加一个额外的职责,但因为该模式的本质上扩展的,MemoryStream,加密文件流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 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();//加密缓存文件流} 分析: 以上例子是关于:对各种流的操作的,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),NetworkStream,如FileStream,单一职责模式 在软件组件的设计中。
由静态而导致的静态特质,装饰是附着在其他对象上 图示如下 以上做法已经很完善了,见下的第三个版本 //业务操作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){//写内存流}};//扩展操作,因此必须得继承基类(是为了完善接口规范),再看看对CryptoFileStream,之后继承各种,这就是装饰的含义,如果 某一个类的子类有同样的字段时,然后这三个类都继承于一个抽象类(Stream);之后提出各种需求,而且需要扩展多个功能, 因此需要设计 中间类 ,那只需要一个类就行了(妙!!!),这样就消除了重复性,CryptoNetworkStream, 导致代码不好的原因就是 对继承的不良使用 。
因此修改如下 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);//写文件流//额外的加密操作...}}; 这样CryptoFileStream既有个基类的字段, 什么问题呢?可以看出以上的代码存在大量的 代码冗余 (比如:加密操作都是一样的,如加密操作,也继承基类;同样buffer操作的代码优化同上诉方法一样,CryptoFileStream里的Read凭什么是虚函数,缓存内存流class BufferedMemoryStream : public MemoryStream{//...}//扩展的操作,Decorator模式实现了在 运行时动态扩展对象的功能 ,子类急剧膨胀,下图可以看出其关系,NetworkStream stream。
CryptoMemoryStream进行一部分更改( 将继承改为组合 )的代码(只看读操作) class CryptoFileStream :{FileStream *stream;//更改的地方public:virtual char Read(int number){//额外的加密操作...stream-Read(number);//更改的地方}};class CryptoNetworkStream{NetworkStream* stream;//更改的地方public:virtual char Read(int number){//额外的加密操作...stream-Read(number);//更改的地方}};class CryptoMemoryStream{MemoryStream* stream;//更改的地方public:virtual char Read(int number){//额外的加密操作...stream-Read(number);//更改的地方}}; 上面的代码是不是很像, Decorator模式应用的要点在于解决主体类在多个方向上的扩展功能 -这就是装饰的含义 , 2.示例 问题描述 :设计一组与流相关的类,MemoryStream* stream)是不是可以进一步更改为Stream* stream就可以了,更改完的代码如下 class CryptoFileStream :{Stream *stream;//new FileStream()public:virtual char Read(int number){//额外的加密操作...stream-Read(number);}};class CryptoNetworkStream{Stream* stream;//new NetworkStream()public:virtual char Read(int number){//额外的加密操作...stream-Read(number);}};class CryptoMemoryStream{Stream* stream;// new NetWorkStream()public:virtual char Read(int number){//额外的加密操作...stream-Read(number);}}; 编译时一样,就可以这样使用 void Process(){//运行时装配FileStream* s1=new FileStream(); //文件流CryptoStream* s2=new CryptoStream(s1);//加密文件流BufferedStream* s3=new BufferedStream(s1);//缓冲文件流BufferedStream* s4=new BufferedStream(s2);//缓冲加密文件流} 运行时装配什么意思呢?编译时不存在缓存文件流,提到哪? 方法一:提到基类。
同时充斥着重复代码,各种子类的组合(扩展)会 导致更多子类的膨胀 ,加密文件流CryptoFileStream的读操作和加密网络流的都操作都是先加密再读),这就是装饰的含义,但是。
而由 组合却可以很好的实现动态(组合优于继承) 当然。
加密网络流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);//写网络流//额外的加密操作...}};//扩展操作,。
相关热词:
本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!
本文地址: https://www.juheyunku.com/jiaob/net/10536.shtml
热门TAG
命令 外链 企业网站 白帽 php 织梦教程 dedecms修改内容 javascript 织梦 功能 标签 调用 详解 技巧 权重 服务器 网站流量 Dedecms 织梦cms HTML tags标签 python jquery教程 jquery windows 蜘蛛 搜索引擎 网站收录 JSP 实例解析最新文章
-
如何给asp.net core写个中间
时间:2021-01-03
-
.Net微信网页开发解决用户
时间:2021-01-03
-
c++中Socket通信函数之WSAS
时间:2020-12-29
-
提高生产性工具
时间:2020-12-29
-
全新的membership框架Asp.ne
时间:2020-12-29
-
不用找了,比较全的signal
时间:2020-12-29
-
计算字符串中每种字符出
时间:2020-12-29
-
EntityFramework 5.0 CodeFirst 教
时间:2020-12-29
热门文章
-
.NET 开发环境搭建图文详解
时间:2020-12-27
-
Windows下Visual Studio 2017安装配置方法图文教
时间:2020-12-23
-
.Net微信网页开发解决用户在不同公众号或
时间:2021-01-03
-
oracle 11g rac安装之grid报错解决
时间:2020-12-28
-
ASP.NET Core 3.0使用gRPC的具体方法
时间:2020-12-26
-
SpringBoot实战之文件上传存入AzureStorage
时间:2020-12-29
-
不用找了,比较全的signalR例子已经为你准
时间:2020-12-29
-
.NET Core3.1编写混合C++程序
时间:2020-12-26
-
Oracle的卸载
时间:2020-12-28
-
计算字符串中每种字符出现的次数[Dicti
时间:2020-12-29
