美文网首页
从IO中学习装饰器模式

从IO中学习装饰器模式

作者: 何甜甜在吗 | 来源:发表于2019-10-17 14:58 被阅读0次

    最近在重学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这些被装饰器类,使用缓冲提高性能

    优缺点

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

    和继承有啥区别

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

    相关文章

      网友评论

          本文标题:从IO中学习装饰器模式

          本文链接:https://www.haomeiwen.com/subject/pfumuctx.html