装饰器模式
定义
装饰器模式又名包装(Wrapper)模式。装饰器模式以对客户端透明的方式拓展对象的功能,是继承关系的一种替代方案。
类图
角色
- 抽象构件(Component)角色:给出一个抽象接口,已规范准备接收附加责任的对象。
- 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类
- 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。
示例
组件接口
public interface Component {
public String getName();
}
具体组件实现类A
public class ComponentImplA implements Component {
private String name;
public ComponentImplA(String name){
this.name = name;
}
@Override
public String getName() {
// TODO Auto-generated method stub
return name;
}
}
具体组件实现类B
public class ComponentImplB implements Component {
private String name;
public ComponentImplB(String name){
this.name = name;
}
@Override
public String getName() {
// TODO Auto-generated method stub
return name;
}
}
装饰器实现组件接口
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component){
this.component = component;
}
@Override
public String getName() {
return component.getName();
}
}
具体的装饰器A,这里新增一个方法appendName;
public class DecoratorImplA extends Decorator {
public DecoratorImplA(Component component) {
super(component);
}
//增加额外的操作
public void appendName(String name){
System.out.println(this.component.getName()+name);
}
}
具体的装饰器B,这里重写原来的getName方法;
public class DecoratorImplB extends Decorator {
public DecoratorImplB(Component component) {
super(component);
}
@Override
public String getName() {
return super.getName()+"|append2";
}
}
测试类
public class DecoratorTest {
public static void main(String[] args) {
Component componentImplA = new ComponentImplA("componentA");
DecoratorImplA decoratorImplA = new DecoratorImplA(componentImplA);
decoratorImplA.appendName("|append1");
System.out.println(new DecoratorImplB(componentImplA).getName());;
}
}
分析
- 装饰器相较于继承来说,可以在运行时保持原来接口不变的情况下动态的给原对象增加新功能,而继承是静态的;
- 跟适配器比较:
- 理想的装饰器模式的装饰者接口跟组件接口应该保持一模一样,这样每次传入一个组件进去,都只对组件接口的各个方法增加功能,返回依旧由组件接口接收,这样调用同一个对象的同一个方法会有不同的实现,调用者完全不必要知道具体调用的是哪个对象,这个也称之为透明装饰器;
- 如果装饰者接口跟组件接口不一致,装饰者接口对组件接口方法进行了扩增,也是增加了新功能,但是如果还是用原组件接口来接收的话,新增的方法需要向下转型才能使用,这就违背了装饰器的初衷,但是组件接口中的方法仍然可以正常使用,因此这种可称之为半透明装饰器;
- 如果只是需要将原来对象或者类转换成另外一个我们需要的对象接口,不增加新功能,这种就是适配器;
- 简单的来理解的话,装饰器用来新加功能,适配器只是用来转换功能;