从IO中学习装饰器模式

最近在重学IO,我们在创建输入输出流的时候总会在构造函数中嵌套很多类,比如:BufferedReader in = new BufferedReader(new FileReader(fileName));,其实这段代码就是装饰器模式的应用,那什么是装饰器模式、有什么应用场景、优缺点是什么?

装饰器模式定义

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构,装饰器模式的类图如下:

装饰器类图

装饰器的角色介绍:

  • 装饰器抽象构件 => Component,为一个接口或抽象类
  • 具体的构建实现类 => ConcreteComponent
  • 装饰器类 => Decorator
  • 具体的装饰器类 => ConcreteDecoratorAConcreteDecoratorB,装饰器类的具体实现,里面必有一个属性指向Componet装饰器抽象构建

装饰器模式Demo

以写简历和hr读简历的例子来讲解装饰器模式

  • 抽象类或接口:Resume.java
    面向接口编程,所以选择了接口方式
    定义了一个自我介绍的方法
    public interface Resume {
        void selfIntroduce();
    }
    
  • 基本实现类:MyResume.java
    public class MyResume implements Resume {
        @Override
        public void selfIntroduce() {
            System.out.println("姓名: 何甜甜");
            System.out.println("求职方向:服务端开发");
        }
    }
    
    光有这些基本信息是不够的,需要有亮点,不然无法在寒冬求职中过简历关,所以我们得再装饰下简历,但前提要求是不动基本实现类
  • 装饰器类:Decorator.java
    public abstract class Decorator implements Resume {
        /**
         * 接口
         */
        private Resume resume;
    
        /**
         * 构造函数
         */
        public Decorator(Resume resume) {
            this.resume = resume;
        }
    
        @Override
        public void selfIntroduce() {
            //调用传入Resume实现类的方法
            resume.selfIntroduce();
        }
    }
    
  • 具体的装饰器类
    可以有多个具体的装饰器类
    • WorkExperienceDecorator.java
        public class WorkExperienceDecorator extends Decorator {
          /**
           * 构造函数
           *
           * @param resume
           */
          public WorkExperienceDecorator(Resume resume) {
              super(resume);
          }
      
          @Override
          public void selfIntroduce() {
             super.selfIntroduce();
             //在装饰一下简历,添加工作奖励
            addWorkExperience() 
          }
      
          public void addWorkExperience() {
              System.out.println("2018-2019:xxx公司打杂");
          }
        }
      
    • OtherDecorator.java
      public class OtherDecorator extends Decorator {
          /**
           * 构造函数
           *
           * @param resume
           */
          public OtherDecorator(Resume resume) {
              super(resume);
          }
      
          @Override
          public void selfIntroduce() {
              super.selfIntroduce();
              //添加其他信息,比如github、个人博客
              addOther();
          }
      
          public void addOther() {
              System.out.println("博客:https://juejin.im/user/5b8f8cc05188255c735f3f1d");
              System.out.println("github:https://github.com/TiantianUpup");
          }
      }
      
  • 测试类
    public class Test {
        public static void main(String[] args) {
            Resume resume = new MyResume();
            //1.添加工作经历
            resume = new WorkExperienceDecorator(resume);
            //2.添加github、博客
            resume = new OtherDecorator(resume);
    
            //hr读简历
            HrReader hrReader = new HrReader();
            hrReader.read(resume);
        }
    }
    

应用场景

装饰器模式就是使用在对已有的目标功能存在不足,需要增强时【不能改变已有类】,并且目标存在抽象接口
IO中应用了大量的装饰器模式,先来看一种类图:

IO类图

附:图片来源
Reader这块来讲解装饰器模式在IO中的应用

  • 抽象类
    Reader,是一个抽象类,里面定义了接口
  • 被装饰的类
    InputStreamReaderCharArrayReaderPipedReaderStringReaderFileReader
  • 装饰器类
    FilterReaderBufferedReader
  • 具体的装饰器类
    BufferedReaderPushbackReader
    FileReader尽管也在第三行,但是FileReader构不成一个具体的装饰器类,因为它不是BufferedReader的子类也不是FilterReader的子类,不持有Reader的引用
    读写IO的时候每次打开文件会非常耗时,我们可以使用BufferedReader装饰FileReader这些被装饰器类,使用缓冲提高性能

优缺点

  • 优点
    可以动态扩展一个实现类的功能而不改变原有实现类
  • 缺点
    由于使用装饰器模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是另一方面,由于使用装饰器模式会产生比使用继承关系更多的对象,更多的对象会使得查错变得困难,特别是这些对象看上去都很像

和继承有啥区别

装饰器模式是多继承的一种替代方式,但是两者之间还是存在一些不同。装饰器模式比较灵活,因为它修饰哪个类是在运行时才确定的,而继承中,继承哪个类是在编写哪个继承类的时候就要确定下来的,即继承是编译时确认

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • JAVA面试题 1、作用域public,private,protected,以及不写时的区别答:区别如下:作用域 ...
    JA尐白阅读 4,860评论 1 0
  • 设计模式分类 总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原...
    lifeline丿毅阅读 4,969评论 0 2
  • 1.在Java中是否可以含有多个类?答:可以含有多个类,但只有一个是public类,public类的类名与文件名必...
    小宇java阅读 1,898评论 0 0
  • I/O的学习之字符流 今天的学习内容 字符流FileReader 字符流FileWriter 字符流的拷贝 带缓冲...
    须臾之北阅读 2,490评论 0 1
  • 我是夜间的行者 手持选梦的神杖 天帝说 它能决定生命的去向 四季星空在我面前 展现出一幅幅璀璨影象 有射手有猎人 ...
    行人a阅读 1,183评论 0 2