本文将讨论Java设计模式中比较重要的模式之一:装饰者模式
该系列其他文章:
- 安卓设计模式(一)面向对象六大设计原则
- 安卓设计模式(二)单例模式
- 安卓设计模式(三)Builder模式
- 安卓设计模式(四)装饰者模式
- 安卓设计模式(五)代理模式
- 安卓设计模式(六)策略模式
- 安卓设计模式(七)模板方法模式
- 安卓设计模式(八)工厂方法模式
装饰者模式
装饰者模式也称为包装模式,属于结构型设计模式
定义:动态地给一个对象添加一些额外的职责.就增加功能来说,装饰模式相比生成子类更为灵活.
使用场景:需要透明且动态的地扩展类的功能时.
UML类图
包括以下几个角色:
- 抽象构件(Component)角色:给出一个抽象接口,规范待装饰者的功能方法。
- 具体构件(ConcreteComponent)角色:待装饰类。
- 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- 具体装饰(ConcreteDecorator)角色:具体装饰者。
举例
Component:抽象组件
/**
* =================中康================
*
* @Author: 陈振
* @Email : 18620156376@163.com
* @Time : 2016/11/1 14:36
* @Action :待装饰者抽象:开发者
*
* =================中康================
*/
public abstract class Coder {
public abstract void dev();//开发公司项目
}
ConcreteComponent:具体组件
/**
* =================中康================
*
* @Author: 陈振
* @Email : 18620156376@163.com
* @Time : 2016/11/1 14:38
* @Action :待装饰者具体实现:安卓开发一枚
*
* =================中康================
*/
public class AndroidCoder extends Coder {
@Override
public void dev() {
Log.i("AndroidCoder", "开发公司的安卓项目");
}
}
Decorator:装饰者抽象
/**
* =================中康================
*
* @Author: 陈振
* @Email : 18620156376@163.com
* @Time : 2016/11/1 14:42
* @Action :装饰者抽闲:具有维护开源项目的增强型功能
*
* =================中康================
*/
public abstract class OpenSource extends Coder {
private Coder mCoder;
public OpenSource(Coder coder) {//注意这里,装饰者会持有待装饰者组件的实例
mCoder = coder;
}
public abstract void fixBug();//修复开源项目中的bug
@Override
protected void dev() {
mCoder.dev();
}
}
ConcreteDecorator:具体装饰者
/**
* =================中康================
*
* @Author: 陈振
* @Email : 18620156376@163.com
* @Time : 2016/11/1 14:44
* @Action :装饰者,具有修复github上项目的bug的功能
*
* =================中康================
*/
public class GithubFixer extends OpenSource {
public GithubFixer(Coder coder) {
super(coder);
}
@Override
public void fixBug() {
Log.i("GithubFixer", "修复github上的bug");
}
@Override
public void dev() {
fixBug();//上班之前先看看开源项目有没有bug需要修复
super.dev();//再开始开发
}
}
实际使用
AndroidCoder androidCoder = new AndroidCoder();//安卓开发者
androidCoder.dev();//以前每天上班就是写代码
//装饰者模式之后
GithubFixer githubFixer = new GithubFixer(androidCoder);//公司项目没那么紧,每天开发之前可以先维护下开源项目
githubFixer.dev();
new GithubFixer(androidCoder).dev();//与以上等价
结果:
AndroidCoder: 修复github上的bug
GithubFixer:开发公司的安卓项目
分析
在这个例子中,安卓程序猿一天的工作就是开发公司的项目,即androidCoder.dev()
,后来想要增强自己的功能,需要维护github上的开源项目,于是便使用了GithubFixer
来装饰自己,即:new GithubFixer(androidCoder).dev()
,这样在每次每天开发之前都会去先维护开源项目,再去开发.
-
对于调用者,这完全是透明的,在所有基础调用的位置,做以下替换就可以:
androidCoder.dev();//==> new GithubFixer(androidCoder).dev(); //当然也可以维护更多社区的项目... new OsChinaFixer(androidCoder).dev();
-
另外,
GithubFixer
不仅仅可以装饰androidCoder
,IosCoder
-JavaCoder
等等都可以装饰,例如:new GithubFixer(iosCoder).dev(); new GithubFixer(phpCoder).dev();
如果你使用继承来为AndroidCoder(ios-php等等)增加fixBug功能,组件类别比较多的情况下,势必会造成体系的臃肿,但是反观装饰者模式,由于是动态的为组价增强功能,则很好的避免了继承体系臃肿的问题.
-
装饰者模式可以链式调用,例如:
new PlayGame(new GithubFixer(iosCoder)).dev;//为组件增加维护开源项目,打游戏的功能
组件的原有功能没有任何破坏,
Coder.dev()
保持内部逻辑;装饰者内部会持有待装饰者组件实例
Android源码中装饰者模式的使用
在源码中装饰者模式被使用的地方还是很多的,最典型的是Context体系,这里简单分析一下:
- Context - 抽象组件
- ContextImpl - 具体组件:继承自Context,实现了Context中的抽象方法;
- ContextWrapper - 装饰者抽象:继承Context,定义了一些增强方法,内部持有Context引用
- ContextThemeWrapper - 具体装饰者父类:实现了ContextWrapper中的抽象方法,提供一些通用实现
- Activity,Service,Application - 具体装饰者实现类:实现全部的装饰方法
关于作者
- 简 书:uncochen
- github:ChenZhen
- 新浪微博:@Chen丶振
- Email:18620156376@163.com