这篇将会介绍装饰者模式(Decorator Pattern),装饰者模式也称为包装模式(Wrapper Pattern),结构型模式之一,其使用一种对客户端透明的方式来动态的扩展对象的功能,同时它也是继承关系的一种替代方案之一,但比继承更加灵活。在现实生活中也可以看到很多装饰者模式的例子,或者可以大胆的说装饰者模式无处不在,就拿一件东西来说,可以给它披上无数层不一样的外壳,但是这件东西还是这件东西,外壳不过是用来扩展这个东西的功能而已,这就是装饰者模式,装饰者的这个角色也许各不相同但是被装饰的对象本质是不变的。
我们的目标是允许类统一扩展,在不修改现有代码的情况下,就可搭配新的行为。如能实现这样的目标,有什么好处呢?这样的设计具有弹性,可以应对改变,可以接受新的功能来应对改变的需求,也就是 OO 原则中的对扩展开放和对修改关闭的开闭原则。
转载请注明出处:http://blog.csdn.net/self_study/article/details/51591709。
PS:对技术感兴趣的同鞋加群544645972一起交流
java/android 设计模式学习笔记目录
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰者模式相比生成子类更加灵活,提供了有别于继承的另一种选择。
装饰者模式可以静态的,或者根据需要可以动态的在运行时为一个对象扩展功能。被装饰者和众多的装饰者都是继承自一个接口,他们有着一样的行为特性。装饰者模式是继承的另一种选择方式,继承是在编译的时候为类添加新的行为,并且这个改变会影响所有原来该类的实体,装饰者模式就不一样,它提供一种能够在运行时根据需要选择不同运行对象的功能。装饰者模式和继承这两种方式的不同之处在某些扩展功能的情况下显得尤为重要,在一些面向对象编程的语言中,类无法在运行时被创建,而且当需要扩张功能时,这些行为往往无法预测,这就意味着在每个可能的情况下,这个类都需要被创建,所以对比之下,装饰者模式优点在于每个装饰者都是对象,在运行时被创建,并且能够在每次使用时根据需要自己组合。
我们现在来看看装饰者模式的 uml 类图:
装饰者模式共有四大角色:
最典型的就是 Java 中的 java.io 包下面的 InputStream 和 OutputStream 相关类了,初学 Java 的时候,看到这些类,头都大了,其实学了装饰者模式之后,再理解这些类就很简单了,画一个简单的类图来表示:
InputStream 类是一个抽象组件, FileInputStream,StringBufferInputStream 和 ByteArrayInputStream 类都是可以被装饰者包起来的具体组件;FilterInputStream 是一个抽象装饰者,所以它的四个子类都是一个个装饰者了。
其次,对于 android 开发工程师来说,最最重要的就应该是“上帝类” Context 和其子类了,这些类我就不用解释了,上一张类图基本就明确了:
所以对于 Application,Activity 和 Service 等类来说,他们只是一个个装饰者,都是用来装饰 ContextImpl 这个被装饰者类,Application 是在 createBaseContextForActivity 方法中,通过 ContextImpl 的静态方法 createActivityContext 获得一个 ContextImpl 的实例对象,并通过 setOuterContext 方法将两者建立关联;Activity 是通过 handleLaunchActivity 方法设置的 ContextImpl 实例,这个方法会获取到一个Activity对象,在performLaunchActivity函数中会调用该activity的attach方法,这个方法把一个ContextImpl对象attach到了Activity中,具体可以看看我的这篇博客,里面详细介绍到了 Activity 的启动过程:android 不能在子线程中更新ui的讨论和分析。别的类在这里就不介绍了,具体的大家可以去网上查阅相关资料。
我们这里以一个图形系统中的 Window 为例,一般情况窗口都是能够垂直或者是左右欢动的,所以为了能够更好的支持 Window 的滑动,给滑动的 Window 加上一个 ScrollBar 是一个不错的方法,为了重用代码,水平滑动的 Window 和垂直滑动的 Window 我们就能够使用装饰者模式去处理,基本类图如下所示:
根据类图,我们首先实现 Window 这个接口:
IWindow.class
public interface IWindow {
void draw();
String getDescription();
}
然后是被装饰者 SimpleWindow 类,它实现了窗口的基本行为:
SimpleWindow.class
public class SimpleWindow implements IWindow {
@Override
public void draw() {
Log.e("shawn", "drawing a window");
}
@Override
public String getDescription() {
return "a window";
}
}
然后是装饰者类角色的抽象父类:
WindowDecorator.class
public abstract class WindowDecorator implements IWindow{
private IWindow window;
public WindowDecorator(IWindow window) {
this.window = window;
}
@Override
public void draw() {
window.draw();
}
@Override
public String getDescription() {
return window.getDescription();
}
}
最后是实现该装饰者父类的装饰者子类:
HorizontalScrollBarDecorator.class
public class HorizontalScrollBarDecorator extends WindowDecorator {
public HorizontalScrollBarDecorator(IWindow window) {
super(window);
}
@Override
public void draw() {
super.draw();
Log.e("shawn", "then drawing the horizontal scroll bar");
}
@Override
public String getDescription() {
return super.getDescription() + " with horizontal scroll bar";
}
}
VerticalScrollBarDecorator.class
public class VerticalScrollBarDecorator extends WindowDecorator {
public VerticalScrollBarDecorator(IWindow window) {
super(window);
}
@Override
public void draw() {
super.draw();
Log.e("shawn", "then drawing the vertical scroll bar");
}
@Override
public String getDescription() {
return super.getDescription() + " with vertical scroll bar";
}
}
最后测试代码:
switch (v.getId()) {
case R.id.btn_horizontal_window:
IWindow horizontalWindow = new HorizontalScrollBarDecorator(new SimpleWindow());
horizontalWindow.draw();
Log.e("shawn", "window description : " + horizontalWindow.getDescription());
break;
case R.id.btn_vertical_window:
IWindow verticalWindow = new VerticalScrollBarDecorator(new SimpleWindow());
verticalWindow.draw();
Log.e("shawn", "window description : " + verticalWindow.getDescription());
break;
}
结果:
com.android.decoratorpattern E/shawn: drawing a window
com.android.decoratorpattern E/shawn: then drawing the horizontal scroll bar
com.android.decoratorpattern E/shawn: window description : a window with horizontal scroll bar
com.android.decoratorpattern E/shawn: drawing a window
com.android.decoratorpattern E/shawn: then drawing the vertical scroll bar
com.android.decoratorpattern E/shawn: window description : a window with vertical scroll bar
代码一目了然,结构清晰。
其实说到底,每一个写过 Android 程序的人都应该用过装饰者模式,因为每写一个 Activity,就相当于是写了一个装饰者类,不经意间就用了装饰者模式,大家想一想是不是,哈哈~~
装饰者模式和代理模式有点类似,很多时候需要仔细辨别,容易混淆,倒不是说会把代理模式看成装饰者模式,而是会把装饰者模式看作代理模式。区分一下,装饰者模式的目的是透明地为客户端对象扩展功能,是继承关系的一种替代方案,而代理模式则是给一个对象提供一个代理对象,并由代理对象来控制对原有对象的引用。装饰者模式应该为所装饰的对象增强功能;代理模式对代理的对象施加控制,但不对对象本身的功能进行增强。
同时有几个要点需要提一下:
这四个都是结构型设计模式,他们有些类似,在实际使用过程中也容易搞混,我们在这就给他们做一个对比:
适配器模式和其他三个设计模式一般不容易搞混,它的作用是将原来不兼容的两个类融合在一起,uml 图也和其他的差别很大。
uml 类图:
装饰者模式结构上类似于代理模式,但是和代理模式的目的是不一样的,装饰者是用来动态地给一个对象添加一些额外的职责,装饰者模式为对象加上行为,而代理则是控制访问。
uml 类图:
桥接模式的目的是为了将抽象部分与实现部分分离,使他们都可以独立地进行变化,所以说他们两个部分是独立的,没有实现自同一个接口,这是桥接模式与代理模式,装饰者模式的区别。
uml 类图:
代理模式为另一个对象提供代表,以便控制客户对对象的访问,管理的方式有很多种,比如远程代理和虚拟代理等,这个在上面有,这里就不说了,而装饰者模式则是为了扩展对象。
uml 类图:
https://github.com/zhaozepeng/Design-Patterns/tree/master/DecoratorPattern
https://en.wikipedia.org/wiki/Decorator_pattern
http://blog.csdn.net/jason0539/article/details/22713711