一、基本概念
1. 定义
装饰者模式,也称为包装模式,允许在不改变原有类结构的前提下,动态地给对象增加新的行为或属性。它通过将对象封装在另一个对象中,使得新对象可以在调用原对象的基础上进行增强。相比子类化,装饰者模式提供了更灵活的解决方案。
该模式的关键在于,它可以在不影响其他对象的情况下,透明地扩展对象的功能。这种特性使得装饰者模式在需要动态调整功能的应用场景中非常有用,如Java I/O流处理。
2. 适用环境
装饰者模式适用于以下情况:
- 需要在不影响其他对象的情况下,动态地为单个对象添加职责。
- 需要支持可以撤销的职责。
- 当不能使用子类化方法进行扩展时,例如有大量独立的扩展需求,或者类定义被隐藏无法生成子类。
3. 角色
- 抽象构件(Component):通常是一个接口或抽象类,定义了组件的基本操作。具体实现由其子类完成。
- 具体构件(Concrete Component):实现了抽象构件定义的操作,是被装饰的对象。
- 装饰角色(Decorator):持有一个抽象构件的引用,负责将客户端请求转发给被装饰对象,并在其基础上进行增强。
- 具体装饰角色(Concrete Decorator):具体的装饰类,继承自装饰角色,实现特定的增强功能。
4. UML图解
二、代码实现
为了更好地理解装饰者模式的工作原理,我们可以通过一个简单的示例来展示其实现过程。
1. 抽象构件——IComponentOutput接口
public interface IComponentOutput { void operator(); }
2. 具体构件——Output类
public class Output implements IComponentOutput { @Override public void operator() { System.out.println("输出字节流"); } }
3. 装饰角色——AbstractBuffer抽象类
public abstract class AbstractBuffer implements IComponentOutput { private IComponentOutput output; public AbstractBuffer(IComponentOutput output) { this.output = output; } @Override public void operator() { output.operator(); } }
4. 具体装饰角色——Buffer1类
public class Buffer1 extends AbstractBuffer { public Buffer1(IComponentOutput output) { super(output); } @Override public void operator() { super.operator(); this.b1(); } void b1() { System.out.println("附加1"); } }
5. 具体装饰角色——Buffer2类
public class Buffer2 extends AbstractBuffer { public Buffer2(IComponentOutput output) { super(output); } @Override public void operator() { super.operator(); this.b2(); } void b2() { System.out.println("附加2"); } }
6. 具体装饰角色——Buffer3类
public class Buffer3 extends AbstractBuffer { public Buffer3(IComponentOutput output) { super(output); } @Override public void operator() { super.operator(); this.b3(); } void b3() { System.out.println("附加3"); } }
以上三个具体装饰类分别实现了不同的附加功能。
7. 测试类——Client类
public class Client { public static void main(String[] args) { IComponentOutput output = new Output(); output.operator(); System.out.println("===定制1==="); AbstractBuffer b1 = new Buffer1(output); AbstractBuffer b2 = new Buffer2(b1); b2.operator(); System.out.println("===定制2==="); AbstractBuffer b3 = new Buffer3(output); b3.operator(); } }
执行结果如下:
输出字节流
===定制1===
输出字节流
附加1
附加2
===定制2===
输出字节流
附加3
补充说明
注意,在定制1的方式中:
AbstractBuffer b1 = new Buffer1(output); AbstractBuffer b2 = new Buffer2(b1);
第二次创建的具体装饰类接收的是已经经过装饰的对象。这使得每次调用都会依次触发所有装饰层的操作,确保每个附加功能都能按顺序执行。