本篇文章已授权微信公众号 顾林海 独家发布
装饰模式是结构型设计模式之一,其在不必改变类文件和使用继承的情况下,动态地扩展一个对象的功能,是继承的替代方案之一。它通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰模式定义:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
装饰模式的结构图:
装饰模式中的角色:
-
Component:抽象组件,可以是接口或是抽象类,被装饰的最原始的对象。
-
ConcreteComponent:组件具体实现类。Component的具体实现类,被装饰的具体对象。
-
Decorator:抽象装饰者,从外类来拓展Component类的功能,但对于Component来说无须知道Decorator的存在。在它的属性中必然有一个private变量指向Component抽象组件。
-
ConcreteDecorator:装饰者的具体实现类。
样板代码实现
抽象组件:
public interface Component {
void operation();
}
组件具体实现类:
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("组件具体实现类...");
}
}
抽象装饰者:
public abstract class Decorator implements Component {
private Component component;
public Decorator(Component component){
this.component=component;
}
@Override
public void operation() {
component.operation();
}
}
装饰者的具体实现类:
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
other();
}
private void other(){
System.out.println("装饰者的具体实现类,做些其他事情...");
}
}
客户端类:
public class Client {
public static void main(String[] arg){
Component component=new ConcreteComponent();
Decorator decorator=new ConcreteDecorator(component);
decorator.operation();
}
}
输出结果:
组件具体实现类...装饰者的具体实现类,做些其他事情...
装饰模式的使用场景:
-
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
-
需要动态地给一个对象增加功能,这些功能可以动态地撤销。
-
当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
优点:
-
通过组合而非继承的方式,动态地扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
-
有效避免了使用继承的方式扩展对象功能而带来的灵活性差、子类无限制扩张的问题。
-
具体组件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体组件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开放封闭原则”。
缺点:
-
因为所有对象均继承于Component,所以如果Component内部结构发生改变,则不可避免地影响所有子类(装饰者和被装饰者)。如果基类改变,则势必影响对象的内部。
-
比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难。对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。所以,只在必要的时候使用装饰模式。
-
装饰层数不能过多,否则会影响效率。