• 设计模式学习(九):装饰器模式


    设计模式学习(九):装饰器模式

    作者:Grey

    原文地址:

    博客园:设计模式学习(九):装饰器模式

    CSDN:设计模式学习(九):装饰器模式

    装饰器模式

    装饰器模式是一种结构型模式。

    顾名思义,就是对某个方法或者对象进行装饰,举个简单的例子,有个圆形类 Circle,我需要把这个圆形的涂上红色,其实就是新增一个装饰器来装饰这个圆形类。

    如果要让装饰器通用一些,可以处理圆形类对应的抽象类 Sharp ,那么对于任意 Sharp 的子类,都可以用红色装饰器来涂红色。

    示例代码如下

    我们先定义 Sharp 这个抽象类

    public abstract class Sharp {
        protected abstract void draw();
    }
    
    • 1
    • 2
    • 3

    然后我们定义 Sharp 的装饰类 SharpDecorator ,这个类是所有装饰器类的抽象类,后续的装饰器只需要实现这个抽象类就可以对 Sharp 进行各种装饰了,

    public abstract class SharpDecorator extends Sharp {
        protected Sharp decoratedSharp;
    
        public SharpDecorator(Sharp decoratedSharp) {
            this.decoratedSharp = decoratedSharp;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    红色装饰器实现这个抽象类即可:

    public class RedSharpDecorator extends SharpDecorator {
        public RedSharpDecorator(Sharp decoratedSharp) {
            super(decoratedSharp);
        }
    
        private static void redIt() {
            System.out.println("[RED]");
        }
    
        @Override
        protected void draw() {
            redIt();
            this.decoratedSharp.draw();
            redIt();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    主方法调用的时候只需要:

    new RedSharpDecorator(new Circle()).draw();
    
    • 1

    UML 图如下:

    image

    说明:

    1. 装饰器类和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类。

    2. 装饰器类是对功能的增强,这也是装饰器模式应用场景的一个重要特点。符合“组合关系”这种代码结构的设计模式有很多,比如代理模式桥接模式,还有现在的装饰器模式。尽管它们的代码结构很相似,但是每种设计模式的意图是不同的。就拿比较相似的代理模式和装饰器模式来说:

    代理模式中,代理类附加的是跟原始类无关的功能;

    装饰器模式中,装饰器类附加的是跟原始类相关的增强功能。

    装饰器模式应用

    在 JDK 中,BufferedInputStream 、 DataInputStream 并非继承自 InputStream ,而是另外一个叫 FilterInputStream 的类。

    这是因为 InputStream 是一个抽象类而非接口,而且它的大部分函数(比如 read()available())都有默认实现,按理来说,我们只需要在 BufferedInputStream 类中重新实现那些需要增加缓存功能的函数就可以了,其他函数只需要复用 InputStream 的默认实现。但实际上,这样做是行不通的。对于即便是不需要增加缓存功能的函数来说,BufferedInputStream 还是必须把它重新实现一遍,简单包裹对 InputStream 对象的函数调用。那 BufferedInputStream 类就无法将最终读取数据的任务,委托给传递进来的 InputStream 对象来完成,DataInputStream 也存在跟 BufferedInputStream 同样的问题。为了避免代码重复,Java I/O 包中抽象出了一个装饰器父类 FilterInputStream,包装了 InputStream 的默认实现

    package java.io;
    
    public class FilterInputStream extends InputStream {
    
        protected volatile InputStream in;
    
        protected FilterInputStream(InputStream in) {
            this.in = in;
        }
    
     
        public int read() throws IOException {
            return in.read();
        }
    
        public int read(byte b[]) throws IOException {
            return read(b, 0, b.length);
        }
    
        public int read(byte b[], int off, int len) throws IOException {
            return in.read(b, off, len);
        }
    
        public long skip(long n) throws IOException {
            return in.skip(n);
        }
    
        public int available() throws IOException {
            return in.available();
        }
    
        public void close() throws IOException {
            in.close();
        }
    
        public synchronized void mark(int readlimit) {
            in.mark(readlimit);
        }
    
        public synchronized void reset() throws IOException {
            in.reset();
        }
    
        public boolean markSupported() {
            return in.markSupported();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    InputStream 的所有的装饰器类( BufferedInputStream 和 DataInputStream )都继承自这个装饰器父类。这样,装饰器类只需要实现它需要增强的方法就可以了,其他方法继承装饰器父类的默认实现。

    其他应用

    • Java 中的 I/O 流, Read/InputStream ,Write/OutputStream

    • Java 中的 UnmodifiableCollection

    • Spring 中的 HttpHeadResponseDecorator, 还有对 Cache 的装饰类 TransactionAwareCacheDecorator

    UML 和 代码

    UML 图

    代码

    更多

    设计模式学习专栏

    参考资料

  • 相关阅读:
    微信小程序报错request:fail -2:net::ERR_FAILED(生成中间证书)
    Pytest+Allure生成可添加附件的测试报告
    数据结构--图
    增强现实基础介绍
    Postman和Jmeter的区别
    linux网络编程---IP地址
    【C语言从入门到放弃 4】字符串,结构体,共用体,位域,typedef详解
    Java版工程行业管理系统源码-专业的工程管理软件-提供一站式服务
    Golang的viper库
    Hadoop伪分布式环境搭建
  • 原文地址:https://blog.csdn.net/hotonyhui/article/details/127795469