- 设计模式之装饰器模式详解
- 一、什么是装饰器模式
- 二、装饰器模式的角色组成
- 三、装饰器模式示例
- 四、装饰器模式优缺点
二、装饰器模式的角色组成装饰器模式(Decorator Pattern) 也称为包装模式(Wrapper Pattern) 是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。装饰器模式的核心是功能扩展,使用装饰器模式可以透明且动态地扩展类的功能。
我们先来看下装饰器模式的通用类图:
- 抽象组件(Component): 可以是一个接口或者抽象类,其充当被装饰类的原始对象,规定了被装饰对象的行为;
- 具体组件(ConcreteComponent): 实现/继承Component的一个具体对象,也即被装饰对象;
- 抽象装饰器(Decorator): 通用的装饰ConcreteComponent的装饰器,其内部必然有一个属性指向Component抽象组件;其实现一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个Component抽象组件,这是强制的通用行为(当然,如果系统中逻辑单一,并不需要实现许多装饰器,那么我们可以直接省略该类,而直接实现一个具体装饰器(ComcreteDecorator)即可);
- 具体装饰器(ConcreteDecorator): Decorator的具体实现类,理论上,每个ConcreteDecorator都扩展了Component对象的一种功能;
我们先创建一个抽象组件Component来规定被装饰对象的行为:
public abstract class Component {
public abstract void operation();
}
创建具体组件ConcreteComponent:
public class ConcreteComponent extends Component {
public void operation() {
System.out.println("具体组件处理业务逻辑");
}
}
创建一个抽象装饰器Decorator:
public abstract class Decorator extends Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
//转发请求给组件对象,可以在转发前后执行一些附加动作
component.operation();
}
}
创建两个具体装饰器ConcreteDecoratorA、ConcreteDecoratorB:
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
//在调用父类的operation方法之前需要执行的操作
private void operationFirst() {
System.out.println("ConcreteDecoratorA前置操作....");
}
//在调用父类的operation方法之后需要执行的操作
private void operationLast() {
System.out.println("ConcreteDecoratorA后置操作....");
}
public void operation() {
//调用父类的方法,可以在调用前后执行一些附加动作
operationFirst(); //添加的功能
//这里可以选择性的调用父类的方法,如果不调用则相当于完全改写了方法,实现了新的功能
super.operation();
operationLast(); //添加的功能
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
//在调用父类的operation方法之前需要执行的操作
private void operationFirst() {
System.out.println("ConcreteDecoratorB前置操作....");
}
//在调用父类的operation方法之后需要执行的操作
private void operationLast() {
System.out.println("ConcreteDecoratorB后置操作....");
}
public void operation() {
//调用父类的方法,可以在调用前后执行一些附加动作
operationFirst(); //添加的功能
//这里可以选择性的调用父类的方法,如果不调用则相当于完全改写了方法,实现了新的功能
super.operation();
operationLast(); //添加的功能
}
}
编写测试类:
public class Client{
public static void main(String[] args){
//首先创建需要被装饰的原始对象(即要被装饰的对象)
Component component = new ConcreteComponent ();
//给对象透明的增加功能A并调用
Decorator decoratorA = new ConcreteDecoratorA(component);
decoratorA.operation();
System.out.println("================================================");
//给对象透明的增加功能B并调用
Decorator decoratorB = new ConcreteDecoratorB(component);
decoratorB.operation();
System.out.println("================================================");
//装饰器也可以装饰具体的装饰对象,此时相当于给对象在增加A的功能基础上在添加功能B
Decorator decoratorBandA = new ConcreteDecoratorB(decoratorA);
decoratorBandA.operation();
}
}
代码测试,控制台输出:
- 优点
- 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用
- 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
- 装饰器完全遵守开闭原则
- 缺点
- 从代码层面来看,使用装饰器模式会出现更多的代码,更多的类,增加程序复杂性
- 动态装饰时,多层装饰时会更复杂



