装饰者模式
装饰者模式,指在不改变现有对象结构的情况下,
动态的
给对象添加一些额外的职责。
- 装饰者模式用于扩展对象的功能,用于代替继承扩展的方式
- 装饰者模式就是一种
简单的包装逻辑
,把你要包装的类传入装饰者类 - 装饰者类
围绕要包装的类做功能的添加
实现 -> 要灵活使用,并不是说一定要一个接口什么的
一个接口,一个实现接口的主类,实现接口的抽象装饰类,具体的装饰类
我们用Java中InputStream举例
- 接口 -> InputStream: 是一个抽象类
-
被装饰者类 -> 已经完成设计的类
FileInputStream
、ByteArrayInputStream
等:相当于装饰者模式的具体组件。实现自InputStream。
-
抽象装饰类 ->
FilterInputStream
:抽象装饰者类。继承InputStream//里面的方法也都是 简单的调用传进来的被装饰者 protected volatile InputStream in; protected FilterInputStream(InputStream in) { this.in = in; } //这里的read()方法不一样会调用到,可能后面包装类直接返回in去被包装类调用了,不一定会结果这个方法 //所以这个方法实际上只是因为有返回值,需要一个返回值而随便写的,重点是构造方法要传入InputStream public int read() throws IOException { return in.read(); } public int available() throws IOException { return in.available(); }
-
具体的装饰类 ->
BufferedInputStream
、CheckedInputStream
等:继承自FilterInputStream- BufferedInputStream举例 -> 在包装类中调用read()会执行各种逻辑
- 但是无论如何最终都会调用
被包装类
自己本身的那个read()
- 但是无论如何最终都会调用
//传入被包装类 public BufferedInputStream(InputStream in, int size) { super(in); } //这个read()中在 fill()方法会调用被包装类自己的read() public synchronized int read() throws IOException { if (pos >= count) { fill(); if (pos >= count) return -1; } return getBufIfOpen()[pos++] & 0xff; } //这里调用被包装类自己的方法,这里getInIfOpen()方法直接返回了被包装类,所以read不会经过抽象类 fill(){ int n = getInIfOpen().read(buffer, pos, buffer.length - pos); }
- BufferedInputStream举例 -> 在包装类中调用read()会执行各种逻辑
-
main方法
public static void main(String[] args) throws Exception { try { // 通过缓冲区数据向输入流添加功能,维护一个内部缓冲区以存储从底层输入流读取的字节: BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\text.txt")); byte byteData; //这里read()方法先调用BufferedInputStream的包装逻辑 //再中间某个位置调回FileInputStream的read()方法 while ((byteData = (byte) bis.read()) != -1) { System.out.print((char) byteData); } bis.close(); } catch (Exception e) { e.printStackTrace(); } }
装饰者模式和代理模式
-
装饰者模式就是用于扩展对象的,和代理模式有相似之处
- 代理模式也可以做到类似装饰者模式这样对一个方法做调整,修改
- 本质上都是一种委托机制
主类委托代理类
完成逻辑主类委托装饰类
完成逻辑
-
网上有这样的说法 -> 代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在
运行时递归地被构造
-
我自己觉得装饰者模式其实就是代理模式的一种特殊场景
-
装饰者模式的
初衷就是添加扩展
,添加一层装饰,所以不能影响对象核心功能,否则就失去了装饰的意义 -
而代理模式虽说主张是控制对象的访问,但其实
也可以作为扩展使用
,AOP就是很好的例子 -
所以用装饰者模式的地方可以用代理模式替换
-
而用代理模式的地方,装饰者模式只能替换一部分,否则他就不叫装饰者,你在瞎写