欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-11 15:57:46
定义 在不改变原有对象的基础之上,将功能附加到对象上 适用场景 详解 在看到定义的时候,可能很多人会想,这不就是继承吗?的确很像,不过是比继承更加有弹性的替代方案。就像原型模式和new之间的关系一样,有区别,但是区别又不是特别大。装饰者一个很重要的词就是动态,他可以灵活的选择要这个功能还是不要。在装 ......

定义

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

适用场景

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

详解

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

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

  实体类创建之后,如果想扩展实体类那么一般的想法是继承,当然继承也是其中方法之一。上面由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());

    }
}

结果

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

具体的内存图

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

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

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

 

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

总结

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