Decorator装饰者模式(结构型模式)
1、需求
假设让我们去设计FCL中的Stream类,该类具有流类的基本功能,除了有各种不同类型的流外(如内存流、文件流、网络流等等),但是在不同的业务场景下,如处理银行业务,需要给相关的内存流进行加密操作,给相关的银行视频业务,进行视频流加密操作.
2、通常性的做法
/// <summary>
/// 流抽象
/// </summary>
public abstract class Stream
{
/// <summary>
/// 读取流的方法
/// </summary>
public abstract void Read(); /// <summary>
/// 流的长度
/// </summary>
public abstract long Length { get; } } /// <summary>
/// 内存流
/// </summary>
public class MemoryStream : Stream
{
public override long Length => ; public override void Read() { } /// <summary>
/// 定义自己的实现
/// </summary>
public virtual void Write() { }
} /// <summary>
/// 文件流
/// </summary>
public class FileStream : Stream
{
public override long Length => ; public override void Read() { } /// <summary>
/// 定义自己的实现
/// </summary>
public virtual void Write() { }
} /// <summary>
/// 加密约束接口
/// </summary>
public interface ICryto
{
/// <summary>
/// 机密方法
/// </summary>
void Cryto();
} /// <summary>
/// 缓冲约束接口
/// </summary>
public interface IBuffered
{
/// <summary>
/// 缓冲方法
/// </summary>
void Buffered();
} /// <summary>
/// 加密内存流
/// </summary>
public class CryptoMemoryStream : MemoryStream, ICryto
{
public override long Length => ; public void Cryto() { } public override void Read() { }
} /// <summary>
/// 加密缓冲内存流
/// </summary>
public class CryptBufferedMemoryStream : MemoryStream, ICryto, IBuffered
{
public override long Length => ; public void Buffered() { } public void Cryto() { } public override void Read() { }
} /// <summary>
/// 加密文件流
/// </summary>
public class CryptoFileStream : FileStream, ICryto
{
public override long Length => ; public void Cryto() { } public override void Read() { }
} /// <summary>
/// 加密缓冲文件流
/// </summary>
public class CryptBufferedFileStream : FileStream, ICryto, IBuffered
{
public override long Length => ; public void Buffered() { } public void Cryto() { } public override void Read() { }
}
ok,上面的设计符合我们的需求,但是如果这个时候多了一个网络流NetStream,而且这个类也需要加密和加密缓冲的功能,这个时候,就需要在写3个子类,如何流的扩展功能增多,有需要额外编写更多的子类来满足需求,这样下去,子类会以指数级增长,所以,显然这种设计是不可取的.
3、问题
由于上面的设计过多的使用了继承来扩展对象的功能,由于继承本身的缺陷,使得这种扩展方式缺乏灵活性,并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承,至继承一个类,但是实现了多个接口).
那么如何使"对象功能的扩展"能够根据需要动态的实现,同时避免功能扩展的同时,子类的膨胀?
4、Decorator装饰者模式
/// <summary>
/// 流抽象
/// </summary>
public abstract class Stream
{
/// <summary>
/// 读取流的方法
/// </summary>
public abstract void Read(); /// <summary>
/// 流的长度
/// </summary>
public abstract long Length { get; } } /// <summary>
/// 内存流
/// </summary>
public class MemoryStream : Stream
{
public override long Length => ; public override void Read() { } /// <summary>
/// 定义自己的实现
/// </summary>
public virtual void Write() { }
} /// <summary>
/// 文件流
/// </summary>
public class FileStream : Stream
{
public override long Length => ; public override void Read() { } /// <summary>
/// 定义自己的实现
/// </summary>
public virtual void Write() { }
} public abstract class StreamDecorator : Stream//接口继承
{
private Stream _stream; public StreamDecorator(Stream stream) { _stream = stream; } public override long Length => ; public override void Read() { }
} /// <summary>
/// 加密功能装饰器
/// </summary>
public class CrytoDecorator : StreamDecorator
{ public CrytoDecorator(Stream stream) : base(stream) { } public override long Length => base.Length; public override void Read()
{
//这里做加密功能的扩展或者不做,直接调用父类的Read操作
base.Read();
}
} /// <summary>
/// 缓冲功能装饰器
/// </summary>
public class CrytoBufferedDecorator : StreamDecorator
{
public CrytoBufferedDecorator(Stream stream) : base(stream) { } public override long Length => base.Length; public override void Read()
{
//这里做缓冲功能的扩展或者不做,直接调用父类的Read操作
base.Read();
}
}
客户端调用代码如下:
public class ThirdSystem
{
public void Run()
{
var fs = new FileStream();
var crytoStream = new CrytoDecorator(fs);//加密文件流
var crytoBufferedDecorator = new CrytoBufferedDecorator(crytoStream);//加密缓冲文件流
var ms = new MemoryStream();
var crytoMsStream = new CrytoDecorator(ms);//加密内存流
var MsCrytoBufferedDecorator = new CrytoBufferedDecorator(crytoMsStream);//加密缓冲内存流
}
}
5、装饰者模式的作用
(1)、主要解决主体类在多个方向上的扩展问题,并非解决多继承产生的"子类泛滥"的问题.
(2)、通过采用组合而非继承的方式,实现了在运行时动态的扩展对象功能的能力,可以更具需要扩展多个功能,避免了使用继承带来的"灵活性差"和"子类泛滥"的问题.
(3)、Stream类在Decorator模式中充当抽象接口的角色,不应该去实现具体的行为,Stream类无需知道Decorator类,Decorator类是从外部来扩展Stream类的功能.
(4)、Decorator类在代码表现上是is a Stream的继承关系,即Decorator继承了Stream类所具有的所有的接口,但是实现上有表现为Has a的关系,即装饰着拥有一个Stream类,可以使用一个或者多个装饰者来包装Stream类,但最终还是只有一个Stream类.
6、实际上微软在设计流系统时,就是使用了这种方式,具体看如下代码:
MemoryStream ms = new MemoryStream(new byte[] {,,, });//内存流
BufferedStream bf = new BufferedStream(ms);//缓冲的内存流
CryptoStream cs = new CryptoStream(bf, null,CryptoStreamMode.Read);//缓冲、机密的流
Decorator装饰者模式(结构型模式)的更多相关文章
- Decorator(装饰)-对象结构型模式
1.意图 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 2.别名 包装器 Wrapper. 3.动机 给某个对象而不是整个类添加一些功能.一个较为灵 ...
- 代理模式/proxy模式/结构型模式
代理模式proxy 定义 为其他对象提供一种代理,并以控制对这个对象的访问.最简单的理解,买东西都是要去商店的,不会去工厂. java实现三要素 proxy(代理)+subject(接口)+realS ...
- 设计模式(十二): Flyweight享元模式 -- 结构型模式
说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面 ...
- 设计模式(十三): Proxy代理模式 -- 结构型模式
设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路 ...
- 设计模式学习之路——Facade 外观模式(结构型模式)
动机: 组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战.如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系 ...
- 设计模式(八):Bridge桥接模式 -- 结构型模式
1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...
- 设计模式(十一):FACADE外观模式 -- 结构型模式
1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子1:一个电源总开关可以控制四盏灯.一个风扇 ...
- 设计模式(十):Decorator装饰者模式 -- 结构型模式
1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继 ...
- 装饰模式/decorator模式/结构型模式
装饰模式Decorator 定义 为对象动态的增加新的功能,实现要求装饰对象和被装饰对象实现同一接口或抽象类,装饰对象持有被装饰对象的实例. java实现要点 定义一个接口或抽象类,作为被装饰者的抽象 ...
随机推荐
- MFCC
在语音识别研究领域,音频特征的选择至关重要.在这里介绍一种非常成功的音频特征——Mel Frequency Cepstrum Coefficient(MFCC),中文名字为梅尔频率倒谱系数.MFCC特 ...
- Foundation-NSOperation-NSInvocationOperation/NSBlockOperation/NSOperationQueue
iOS多线程编程技术之NSThread.Cocoa NSOperation.GCD 线程之间的通信 iOS开发系列--并行开发其实很容易 GCD由浅入深学习 iOS多线程NSOperation/Que ...
- hdu 4940 数据太水...
http://acm.hdu.edu.cn/showproblem.php?pid=4940 给出一个有向强连通图,每条边有两个值分别是破坏该边的代价和把该边建成无向边的代价(建立无向边的前提是删除该 ...
- shell 命令之 crontab
crontab是shell命令中的定时任务: crontab -e 进入当前定时任务的vim页面 每行是一个独立的定时脚本,使用和vim的语法部署定时任务 如下图: 脚本执行周期设置 可以用下面的网页 ...
- Advice from an Old Programmer
You’ve finished this book and have decided to continue with programming. Maybe it will be a career f ...
- cxRichEdit1获取EXCEL的区域图片
cxRichEdit1获取EXCEL的区域图片 搞了好久却原来其实太简单: cxRichEdit1.Clear;Clipboard.Clear;ActiveSheet.cells[2, iCol] ...
- iOS_UIWebView字体大小、字体颜色、背景色
前段时间需要修改webView背景色,上stackoverflow搜了很久没有找到结果,百度搜索,各种转载,各种坑爹,搜出来的都只有字体大小和字体颜色,页面背景没有看到,本人发布方法,希望可以帮助到更 ...
- 2015-2016-1 学期《软件工程》学生名单-- PS:教材使用《构建之法》第二版 --邹欣著
1208053044 王威 男 1313023001 饶阳梅 女 1313023002 应蕾蕾 女 1313023004 袁立萍 女 1313023005 黎洋阳 女 1313023006 蒋欣 女 ...
- 在WPF中将图片转换成3D图像并可以旋转
时光偷走的,永远都是我们眼皮底下看不见的珍贵. https://pan.baidu.com/s/14dk-OU2SR0nxXj2bL4bVpQ 源码网站https://www.codeproject. ...
- .Net下EF的简单实现
1.连接SQLServer,创建数据库TestDB; 2.添加EF引用,点击工具-NuGet包管理器-管理解决方案的NuGet程序包, 搜索EntityFramework包,点击安装: 3.在Web. ...