当前位置: 首页 > news >正文

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 => 1000000000000000;

            public override void Read() { }

            /// <summary>
            /// 定义自己的实现
            /// </summary>
            public virtual void Write() { }
        }

        /// <summary>
        /// 文件流
        /// </summary>
        public class FileStream : Stream
        {
            public override long Length => 1000000000000000;

            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 => 1000000000000000;

            public void Cryto() { }

            public override void Read() { }
        }

        /// <summary>
        /// 加密缓冲内存流
        /// </summary>
        public class CryptBufferedMemoryStream : MemoryStream, ICryto, IBuffered
        {
            public override long Length => 100000000000;

            public void Buffered() { }

            public void Cryto() { }

            public override void Read() { }
        }

        /// <summary>
        /// 加密文件流
        /// </summary>
        public class CryptoFileStream : FileStream, ICryto
        {
            public override long Length => 1000000000000000;

            public void Cryto() { }

            public override void Read() { }
        }

        /// <summary>
        /// 加密缓冲文件流
        /// </summary>
        public class CryptBufferedFileStream : FileStream, ICryto, IBuffered
        {
            public override long Length => 100000000000;

            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 => 1000000000000000;

            public override void Read() { }

            /// <summary>
            /// 定义自己的实现
            /// </summary>
            public virtual void Write() { }
        }

        /// <summary>
        /// 文件流
        /// </summary>
        public class FileStream : Stream
        {
            public override long Length => 1000000000000000;

            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 => 1000000000000;

            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[] {1,2,3,4 });//内存流
            BufferedStream bf = new BufferedStream(ms);//缓冲的内存流
            CryptoStream cs = new CryptoStream(bf, null,CryptoStreamMode.Read);//缓冲、机密的流

 

转载于:https://www.cnblogs.com/GreenLeaves/p/9820149.html

相关文章:

  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • Anaconda3启动ipython的几种方式
  • QueryParser
  • SqlService 索引原理
  • 第五次实验
  • Sherpa | Complete Navigation System 介绍与教材
  • 「postgres」导出数据以及分割数据
  • C#和asp.net执行外部EXE程序
  • 2018.10.23-dtoj-1608新三国争霸(fight)
  • 玩转html5(三)---智能表单(form),使排版更加方便
  • 推荐C++程序员阅读《CLR via C#》
  • 高级 Vue 组件模式 (7)
  • 第一天在某品牌电脑店工作
  • 项目启动时出错的处理
  • 蟠桃记
  • 【Leetcode】101. 对称二叉树
  • android 一些 utils
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • CSS 三角实现
  • MobX
  • Netty 4.1 源代码学习:线程模型
  • php的插入排序,通过双层for循环
  • python 学习笔记 - Queue Pipes,进程间通讯
  • rabbitmq延迟消息示例
  • spring cloud gateway 源码解析(4)跨域问题处理
  • Vue 2.3、2.4 知识点小结
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • 百度地图API标注+时间轴组件
  • 不上全站https的网站你们就等着被恶心死吧
  • 服务器之间,相同帐号,实现免密钥登录
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 前端知识点整理(待续)
  • 数据可视化之 Sankey 桑基图的实现
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 自定义函数
  • Linux权限管理(week1_day5)--技术流ken
  • raise 与 raise ... from 的区别
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • Spring Batch JSON 支持
  • ​卜东波研究员:高观点下的少儿计算思维
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #NOIP 2014# day.2 T2 寻找道路
  • ${ }的特别功能
  • ( 10 )MySQL中的外键
  • (20050108)又读《平凡的世界》
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (二)Linux——Linux常用指令
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (未解决)macOS matplotlib 中文是方框
  • (小白学Java)Java简介和基本配置
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>