装饰模式也叫包装模式,是一种结构型设计模式,主要是提供一种扩展类功能的方式。在安卓世界中,许多带有wrapper
字符串的类名都运用了这种设计模式。
定义
不采用生成子类的方式,透明并且动态的给一个类添加额外的功能
场景
- 需要透明且动态的扩展一个类的功能时
角色
抽象组件
被装饰的原始类,可以是一个接口或者抽象类
具体组件
被装饰的原始类的具体实现
抽象装饰者
装饰组件的类,一般是抽象类,继承自抽象组件,并且持有一个抽象组件的引用
具体装饰者
抽象装饰者的具体实现,装饰关系较简单时,抽象装饰者和具体装饰者可以由一个类实现
代码说明
在大多数情况下,抽象包装者和具体包装者是由一个类来承担。这样可以省略抽象包装者,减少类文件数量。下面我们来看下一个场景的实现。
一个组件有一个jump
方法,只是简单输出一句话,我们想通过装饰者模式在该方法的调用前后输出一条语句。下面来看一下具体的实现。
首先我们定义一个抽象组件接口,接口内有一个jump
方法。
/**
* 抽象组件接口
*/
public interface IComponent {
/**
* 需要包装的方法
*/
void jump();
}
然后通过实现的方式来创建具体需要被装饰的类
/**
* 组件具体实现类
*/
public class ComponentImpl implements IComponent {
/**
* 需要包装的具体方法
*/
@Override public void jump() {
System.out.println("调用具体组件类的方法");
}
}
最后,是我们的装饰类。
/**
* 装饰对象类
*/
public class ComponentWrapper implements IComponent {
private IComponent realComponent;
/**
* 需要装饰的方法
*/
@Override public void jump() {
step1();
realComponent.jump();
step2();
}
/**
* 装饰1
*/
protected void step1() {
System.out.println("方法前面调用包装类的包装方法1");
}
/**
* 装饰2
*/
protected void step2() {
System.out.println("方法后面调用包装类的包装方法2");
}
}
我们来看下具体使用。假设原始组件需要调用jump
方法。包装后,可以这样调用。
public static void main(String[] args) {
// 包装前调用
ComponentImpl component = new ComponentImpl();
component.jump();
// 装饰后调用
ComponentWrapper wrapper = new ComponentWrapper(component);
wrapper.jump();
}
在装饰前,调用原始对象的jump
方法,只会打印
调用具体组件类的方法
而装饰后,则会打印
方法前面调用包装类的包装方法1
调用具体组件类的方法
方法后面调用包装类的包装方法2
这样,在方法一和方法二中就可以扩展组件具体实现类的jump
方法。
关于安卓源码
开篇说过,在安卓世界中,许多带有wrapper
字符串的类名都运用了这种设计模式。比如ContextWrapper
、ContextThemeWrapper
等,这种形式的装饰可以为类提供额外的功能,同时,将包装方法的部分装饰逻辑以抽象方法的形式进行写入,那么子类就可以进行更加简单的方法装饰。
总结
装饰模式是一种扩展类功能的设计模式,与代理模式有些相似。代理模式是通过代理的方式来控制类的访问等,而装饰模式是为类提供额外的功能,在某种程度上,是继承的一种替代品。