装饰模式
定义
装饰者模式又称为包装(wrapper)模式。装饰者模式对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
模板
抽象构件(Component)角色:给出一个抽象接口,以规范准备接受附加责任的对象。
具体构件(ConCreteComponent)角色:定义一个将要接受附加责任的类。
装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。
实例
a) 客户端埋点:经常将回调接口再包装一层,在包装层完成埋点或者其它非主功能的辅助代码
例: 对下载回调listener包装一层,进行下载的埋点。
b) 添加额外的辅助功能: 某个异步回调接口,可能出现回调收不到的bug,这时想设计一种 带自动超时功能的回调:
// 原listener
public interface IListener<T> {
void onSuccess(T result);
void onError(String errorCode, String errorDesc);
}
// 带自动超时功能的listener
public class AutoTimeoutResultListener<T> extends AbstractAutoTimeout
implements IListener<T> {
private IListener<T> mListener;
public AutoTimeoutResultListener(IListener<T> listener) {
mListener = listener;
}
@Override
public synchronized void onSuccess(T result) {
mListener.onSuccess(result);
}
@Override
public synchronized void onError(String errorCode, String errorDesc) {
mListener.onError(errorCode, errorDesc);
}
@Override
synchronized void onTimeout() {
mListener.onError(Constants.ERROR_CODE_TIME_OUT, "IListener time out.");
}
}
装饰模式的简化:
(1) 只有一个ConcreteComponent时,可以考虑去掉抽象的Component类,把Decorator作为ConcreteComponent的子类。
(2) 如果只有一个ConcreteDecorator类,可以将Decorator类和ConcreteDecorator的责任合成一个类。
透明性要求:
装饰模式对客户端的透明性要求程序不要声明Decorator类型的变量,而应该声明Component接口变量。
半透明的装饰模式:
纯粹的装饰模式已经很难找到了,装饰模式的用意是在不改变接口的前提下,增强类的性能。在增强性能时,需要建立新的方法,但是纯粹的装饰模式无法通过Component调用新建立的方法,这时候需要破坏透明性,才能使用新方法。
半透明的装饰模式是介于装饰模式和适配器模式之间的,装饰模式和适配器模式都是“包装模式”,它们都通过封装其他的对象达到设计的目的,但是邢台有很大区别。
理想的装饰模是在被装饰对象进行功能增强时,要求具体的构件角色、装饰角色的接口和抽象构件角色的接口完全一致。而适配器并不要求对原对象进行增强,但会改变对象的接口,以便和目标接口相符合。
优点
- 对原有代码的侵入性很小,可以在不改变原有代码结构的同时增加新的功能,如遇到紧急上线等情况不失为一种好的解决方法。
- 可以在装饰类中增加新的功能/增强原有的功能,也符合职责单一原则,装饰类专门做某种处理(埋点/超时处理)
缺点
- 增加新的类
- 多层装饰比较复杂,影响代码的维护及可读性
适用场景
- 需求开发紧急,添加新功能
- 普通的添加新功能也可以使用该种方法
其它实例: