zoukankan      html  css  js  c++  java
  • 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);//缓冲、机密的流
  • 相关阅读:
    20200318
    20200317
    Thinkphp 操作多个数据库
    base格式图片转文件存储
    Thinkphp POST 和 GET 传值
    Thinkphp调用微信扫一扫实例,学会再也不怕客户在微信提的奇葩要求了
    centos 安装ngnix mysql php
    PHP 区分微信、支付宝、QQ扫码
    PHP秒数计算时分秒
    Thinkphp 获取访问者的ip
  • 原文地址:https://www.cnblogs.com/GreenLeaves/p/9820149.html
Copyright © 2011-2022 走看看