• 结合JDK源码看设计模式——装饰者模式


    定义

      在不改变原有对象的基础之上,将功能附加到对象上

    适用场景

    1. 扩展一个类的功能
    2. 动态的给对象增加功能,当功能不需要的时候能够动态删除

    详解

      在看到定义的时候,可能很多人会想,这不就是继承吗?的确很像,不过是比继承更加有弹性的替代方案。就像原型模式和new之间的关系一样,有区别,但是区别又不是特别大。装饰者一个很重要的词就是动态,他可以灵活的选择要这个功能还是不要。在装饰者中要有四个角色:抽象的实体类,具体的实体类,抽象的装饰者,具体的装饰者。下面画一个大致的UML图

      实体类创建之后,如果想扩展实体类那么一般的想法是继承,当然继承也是其中方法之一。上面由UML图就可以看出,在装饰者模式下,我们可以通过装饰类下的扩展功能实现对抽象实体类的包装。当我们需要扩展功能就多加一个扩展功能,不需要扩展功能就不用添加,是一个很动态的扩展方式。下面具体看代码解析。

    抽象实体类

    public abstract class abstractCake {
        protected abstract String getCake();
        protected abstract int cost();
    
    }

    实体类

    public class cake extends abstractCake{
        @Override
        protected String getCake() {
            return "蛋糕";
        }
    
        @Override
        protected int cost() {
            return 100;
        }
    }

    抽象装饰类(可以抽象也可以不抽象)

    public class AbstractDecorator extends abstractCake {
        private abstractCake abstractcake;
    
        public AbstractDecorator(abstractCake abstractcake) {
            this.abstractcake = abstractcake;
        }
    
    
    
        @Override
        protected String getCake() {
            return this.abstractcake.getCake();
        }
    
        @Override
        protected int cost() {
            return this.abstractcake.cost();
        }
    }

    扩展功能1

    public class FruitDecorator extends AbstractDecorator {
        public FruitDecorator(abstractCake abstractcake) {
            super(abstractcake);
        }
    
    
    
        @Override
        protected String getCake() {
            return super.getCake()+" 加一层水果";
        }
    
        @Override
        protected int cost() {
            return super.cost()+20;
        }
    }

    扩展功能2

    public class SugerDecorator extends AbstractDecorator{
        public SugerDecorator(abstractCake abstractcake) {
            super(abstractcake);
        }
    
    
    
        @Override
        protected String getCake() {
            return super.getCake()+" 多加糖";
        }
    
        @Override
        protected int cost() {
            return super.cost()+10;
        }
    }

    测试类

    public class Test {
        public static void main(String[] args) {
    
            abstractCake ac=new cake();
            ac=new FruitDecorator(ac);
            ac=new SugerDecorator(ac);
            System.out.println(ac.getCake());
    
        }
    }

    结果

    具体的内存图

      可以很清楚的看见ac这个抽象类下面一层层包着实体类,解析的时候每一层的包装类的getCake()方法都会送回给抽象实体类,而我的getCake()方法实现的是字符串增加。后面如果我还需要一层水果,那么我就多装饰一次。如果用继承实现,那么我要两层水果,不要糖,那么我就还需要再定义一个实现两层水果的子类,而装饰者模式就只需要修改客户端的ac类实现就行。在JDK中装饰者模式用的最出名的莫过于IO流了,以InputStream为例子。下面是UML图

      这就是典型的装饰者。平常我们只需要FileInputStream来读取文件,当我们有一些特殊功能需要,如:BufferedInputStream(完成了缓存功能,使读取文件速度大大提升)和DataInputStream(把byte转换成Java基本数据类型)我们就可以装饰一下InputStream,即灵活又方便。这样使得我们对FileInputStream流的处理更能达到我们想要的预期。当你理解了装饰者模式,我推荐你看这篇博客。这样你就能很好的理解IO流的操作。

    总结

      装饰者模式是一个比继承更加灵活的扩展方式,要记住装饰者模式必不可少的4个类:抽象的实体类,具体的实体类,抽象的装饰者,具体的装饰者。再结合上面推荐的博客,我相信你不但能理解装饰者,还能更加清晰的理解JDK中的IO流

  • 相关阅读:
    java抽象类和接口
    java的三大特征:封装,继承和多态
    java的数组
    django 4.get接口开发
    django 3.post接口开发
    C# 程序启动最小化至任务栏及闪烁
    续Html5
    使用intellij idea搭建MAVEN+SSM(Spring+SpringMVC+MyBatis)框架
    Spring MVC拦截器
    Html5高级
  • 原文地址:https://www.cnblogs.com/Cubemen/p/10658183.html
Copyright © 2020-2023  润新知