1. 概念
动态地给一个对象增加一些额外的职责,就增加对象功能而言,装饰模式比生成子类实现更加灵活,装饰模式是一种对象结构型模式。可以是继承的一种替代。
2. 使用场景
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象增加职责;
- 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式;
3. UML
- Component:抽象组件,可以是一个接口或抽象类,是被装饰的原始对象;
- ConcreteComponent:组件的具体实现类。是被装饰的具体对象;
- Decorator:抽象的装饰者。职责是装饰被装饰的对象。内部一定有一个对被装饰者的引用。一般情况下也是一个抽象类,根据具体逻辑实现不同的子类。如果逻辑简单可以直接是实现类;
- ConcreteDecoratorA,B:具体的装饰者。
先抽象组件类:
public abstract class Component {
public abstract void operate();
}
组件的一个具体实现类,也就是被装饰者者:
public class ConcreteComponent extends Component {
@Override
public void operate() {
System.out.println("被装饰者的操作");
}
}
抽象的装饰者,持有一个被装饰者的引用:
public abstract class Decorator extends Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operate() {
component.operate();
}
}
具体的两个装饰者,拓展功能:
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operate() {
operateA();
super.operate();
operateB();
}
private void operateA(){
System.out.println("装饰者A在被装饰者的操作之前加些操作");
}
private void operateB(){
System.out.println("装饰者A在被装饰者的操作之前后加些操作");
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operate() {
operateA();
super.operate();
operateB();
}
private void operateA(){
System.out.println("装饰者B在被装饰者的操作之前加些操作");
}
private void operateB(){
System.out.println("装饰者B在被装饰者的操作之前后加些操作");
}
}
客户端调用:
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent();
ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(component);
ConcreteDecoratorB concreteDecoratorB = new ConcreteDecoratorB(component);
concreteDecoratorA.operate();
concreteDecoratorB.operate();
}
}
输出:
4. 优点
- 对于扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加;
- 可以通过一种动态的方式来扩展一个对象的功能;
- 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些类的不同排列方式
5. 缺点
- 会生成额外的类,增加系统复杂度。
- 由于装饰可以层层包装,交叉包装,如果包装的很深的话,调试排错会比较麻烦,也不容易理解。