12 装饰模式
12.1 装饰模式概述
Decorator Pattern: 动态地给一个对象增加一些额外的职责。提供一种比使用子类更加灵活的方案来扩展功能。
装饰模式是一种用于替代继承的技术,通过一种无须定义子类的方式给对象动态增加职责,使用对象之间的关联关系替代类之间继承关系。
装饰模式结构图如下所示:
12.2 装饰模式实现
12.2.1 抽象构件类
它是具体构件类和抽象装饰类的共同父类,它的引入使得客户端可以以一致的方式处理未装饰的对象和已装饰的对象,实现客户端的透明操作。
public abstract class Component {
public abstract void operation();
}
12.2.2 具体构件类
实现抽象构件中声明的方法,装饰类可以给它增加额外的方法。
public class ConcreteComponent extends Component {
public void operation() {
// 业务代码
}
}
12.2.3 抽象装饰类
用于给具体构件类增加职责,但是具体增加的职责在其子类中实现。
public class Decorator extends Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
// 调用原有业务方法
component.operation();
}
}
12.2.4 具体装饰类
负责向具体构件中添加新的职责。
public class ConcreteDecorator extends Decorator {
public concreteDecorator(Component component) {
super(component);
}
public void operation() {
super.operation();
// 新增的职责
addMethod();
}
public void addMethod() {
// 新增职责逻辑
}
}
12.2.5 客户端调用
public class Client {
public static void main(String[] args) {
Component component, decorator;
component = new ConcreteComponent();
decorator = new ConcreteDecorator(component);
// 一致的方式处理未装饰的对象和已装饰的对象
componet.operation();
decorator.operation();
}
}
12.3 透明装饰模式与半透明装饰模式
12.3.1 透明装饰模式
上述装饰模式的实现即为透明装饰模式,要求客户端完全针对抽象编程。装饰模式的透明性要求客户端程序将对象声明为抽象构件类型,可以一致的处理装饰对象和未装饰对象。
但是在某些情况下,有些新增行为需要单独被调用,此时如果使用透明装饰模式,则无法一致的处理装饰前的对象和装饰后的对象(装饰后的对象需要强制类型转换调用新增行为)。
12.3.2 半透明装饰模式
为了能够调用到新增的方法,不得不用具体装饰类型来定义装饰之后的对象,而具体构件对象可以使用抽象构件声明,这种装饰模式则称为半透明。
public class Client {
Component component;
component = new ConcreteComponent();
component.operation();
ConcreteDecorator decorator = new ConcreteDecorator(component);
decorator.operation();
decorator.addMethod();
}
半透明模式可以给系统带来更多的灵活性,使用起来也非常方便;但是其缺点是客户端需要区别的对象装饰对象和未装饰对象。
12.4 装饰模式优/缺点
使用场景:Java I/O 输入流和输出流
装饰模式的优点主要如下:
- 对于扩展一个类的功能,装饰模式比继承更加灵活
- 可以对一个对象进行多次装饰,通过使用不同的装饰类得到功能更强大的对象
- 具体构件类和具体装饰类可以独立变化,用户根据需要增加新的构件类和装饰类,无须修改原有代码,符合开闭原则
装饰模式的缺点主要如下:
- 装饰模式提供了一种比继承更灵活的方式,同时也比继承更加易于出错,排错也更加困难,对于多次装饰的对象