最近在重学IO,我们在创建输入输出流的时候总会在构造函数中嵌套很多类,比如:BufferedReader in = new BufferedReader(new FileReader(fileName));,其实这段代码就是装饰器模式的应用,那什么是装饰器模式、有什么应用场景、优缺点是什么?
装饰器模式定义
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构,装饰器模式的类图如下:
装饰器的角色介绍:
- 装饰器抽象构件 =>
Component
,为一个接口或抽象类 - 具体的构建实现类 =>
ConcreteComponent
- 装饰器类 =>
Decorator
- 具体的装饰器类 =>
ConcreteDecoratorA
,ConcreteDecoratorB
,装饰器类的具体实现,里面必有一个属性指向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"); } }
- WorkExperienceDecorator.java
- 测试类
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
中应用了大量的装饰器模式,先来看一种类图:
附:图片来源
以
Reader
这块来讲解装饰器模式在IO中的应用
- 抽象类
Reader
,是一个抽象类,里面定义了接口 - 被装饰的类
InputStreamReader
、CharArrayReader
、PipedReader
、StringReader
、FileReader
- 装饰器类
FilterReader
、BufferedReader
- 具体的装饰器类
BufferedReader
、PushbackReader
FileReader
尽管也在第三行,但是FileReader
构不成一个具体的装饰器类,因为它不是BufferedReader
的子类也不是FilterReader
的子类,不持有Reader
的引用
读写IO
的时候每次打开文件会非常耗时,我们可以使用BufferedReader
装饰FileReader
这些被装饰器类,使用缓冲提高性能
优缺点
- 优点
可以动态扩展一个实现类的功能而不改变原有实现类 - 缺点
由于使用装饰器模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是另一方面,由于使用装饰器模式会产生比使用继承关系更多的对象,更多的对象会使得查错变得困难,特别是这些对象看上去都很像
和继承有啥区别
装饰器模式是多继承的一种替代方式,但是两者之间还是存在一些不同。装饰器模式比较灵活,因为它修饰哪个类是在运行时才确定的,而继承中,继承哪个类是在编写哪个继承类的时候就要确定下来的,即继承是编译时确认
网友评论