专栏首页GreenLeavesDecorator装饰者模式(结构型模式)

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);//缓冲、机密的流

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Bridge桥接模式(结构型模式)

     现有一个需求,一个游戏系统需要构建不同风格的房屋,暂不考虑其他设计模式,需要能实现在PC端、移动端....等等多个平台的构建.最简单的实现方式如下:

    郑小超.
  • .Net 从零开始构建一个框架之基本实体结构与基本仓储构建

    本系列文章将介绍如何在.Net框架下,从零开始搭建一个完成CRUD的Framework,该Framework将具备以下功能,基本实体结构(基于DDD)、基本仓储...

    郑小超.
  • FactoryMethod工厂方法模式(创建型模式)

    整个抽象的游戏设施建造系统相对变化较慢,本例中只有一个Build的创建方法,而Build内部的方法实现,该实现依赖与各种具体的实现,而这些实现变化的非常频繁,现...

    郑小超.
  • 温故而知新:设计模式之装饰模式(Decorator)

    小时候对日本的动画片十分着迷,“圣斗士”是我的最爱;长大后也曾经一度对“海贼王”十分痴迷;大学看武侠小说时,也特别喜欢那种主人公有奇遇的情况:吃到一颗千年异果,...

    菩提树下的杨过
  • springboot整合druid连接池

    喜欢天文的pony站长
  • 使用iText5来处理PDF

    项目要求,通过pdf模板,把用户提交的数据保存到一个PDF文件中。其中有文字内容,也有图片。之前选了aspose.pdf,因为抠门,不能花钱买,就从网上找的的开...

    徐大嘴
  • 用命令模式实现撤销与恢复 命令模式定义撤销与重做功能就此实现。整个过程中,最关键部分是命令对象的封装以及控制类与具体工厂类耦合的解除。

    通过 ICommand 接口,实现了控制类与调用者的解耦。 * 下面通过一个简单的实例来详细说明这种解耦以恢复撤销是如何实现。 假定有一个风扇,当前有...

    用户2434869
  • Web API系列之三 基本功能实现

    Web API系列之二讲解了如何搭建一个WebApi的基架,本文主要在其基础之上实现基本的功能.下面开始逐步操作: 一、配置WebApi的路由-用于配置外部如何...

    郑小超.
  • Android MVP 构架初试

    目前讨论MVP MVVM 的架构也来越多,这种构架也很适合Android。研究MVP记录如下

    Javen
  • C# http Get/POST请求封装类

    http://www.sufeinet.com/thread-3-1-1.html

    跟着阿笨一起玩NET

扫码关注云+社区

领取腾讯云代金券