很多同学都看过《皇帝的新衣》,它是丹麦作家安徒生创作的童话,讲述的是一个愚蠢的皇帝被两个骗子愚弄,穿上了一件看不见的新装,赤裸裸的进行游行大典的故事。
对于皇帝老儿来说,他的这件新衣为什么对于他来说起不到装饰的效果呢?
下面我们就来分析一下,对于装饰来说,装饰以后要比原来的状态至少是更好看的,或者说是功能更强的,但是愚蠢的皇帝显然没有任何装饰,自身的供能也没有增强,当然我们从这个故事中可以说明这皇帝没皇帝有学习过装饰模式,所以有必要给他普及一下。
下面我将详细的讲解一下装饰模式:
装饰模式是什么
简单的说:给一个对象添加一些额外的功能。(比如我们给皇帝穿了件新衣服)
思考:我们想要给一个对象添加一些额外的功能,我们可以有几种做法?
1、采用继承。
比如TextView和EditText,EditText继承了TextView,EditText中不仅有TextView的功能,还有一些自己特有的功能。
2、采用静态代理或者动态代理。
请看这篇章:juejin.cn/post/705286…
其中实战篇中静态代理通过在内部封装不同API下的通知来实现各个android版本下通知的实现,现相当于通知功能的增强。
通过动态代理来代理Retrofit的接口API,来实现接口的增强功能,内部封装了OkHttp的请求体和请求的过程。
3、采用装饰模式。
4、适配器模式。
请看这篇文章:juejin.cn/post/705415…
适配器模式解决了2个问题,一个是接口API不匹配的问题,一个是统一输出的问题。
那么接口API不匹配,我们通过适配器,封装出来了另外的接口,这个接口也是满足要求的,那么我们认为就是功能的一种增强。
下面我们学习一下装饰模式的使用场景
装饰模式的使用场景
需要**扩展(增强)**类的功能时。
装饰模式的UML类图
装饰模式的模板代码
根据UML类图,生成的模板代码如下:
第一步:定义被装饰的组件接口,内部只有一个方法。
package com.example.createproject;
/**
* 抽象组件
*/
public abstract class Component {
public abstract void operate();
}
第二步:定义具体的被装饰组件。
package com.example.createproject;
import android.util.Log;
/**
* 具体的被装饰组件
*/
public class ConcreteComponent extends Component{
private static final String TAG = "ConcreteComponent";
@Override
public void operate() {
Log.e(TAG,"ConcreteComponent 执行");
}
}
第三步:定义装饰着基类。
package com.example.createproject;
/**
* 装饰着抽象是为了有更多的装饰者
*/
public class Decorator extends Component{
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operate() {
component.operate();
}
}
第四步:定义具体的装饰者。
package com.example.createproject;
/**
* 具体的装饰者
*/
public class ConcreteDecorator extends Decorator{
public ConcreteDecorator(Component component) {
super(component);
}
public void operate1(){
}
public void operate2(){
}
@Override
public void operate() {
// 装饰的逻辑
operate1();
// 被装饰组件执行逻辑
super.operate();
// 装饰的逻辑
operate2();
}
}
第五步:装饰模式的使用。
// 定义原始组件
Component component = new ConcreteComponent();
// 定义装饰器
Decorator decorator = new ConcreteDecorator(component);
// 执行包装以后的逻辑
decorator.operate();
思考:装饰者模式的模板代码 和 代理模式的模板代码非常的相似。都是注入被装饰的类到装饰类或者代理类中。
思考:设计模式很多时候的边界不是很清晰,有的代码,也可以认为是装饰模式,也可以认为是代理模式,我们不需要纠结于设计模式的结构,而是应该关注它的思想。
下面我们学习一下Android源码中装饰模式的体现
源码中装饰模式的体现
第一步:寻找被装饰者接口
Context类中有startActivity方法。
第二步:寻找被装饰者。
ContextImpl:它是Context的实现类,在这个类中,实现了startActivity方法。
第三步:寻找装饰者基类。
ContextWrapper:在这个类中,首先在构造中注入了Context,赋值给了mBase变量,然后再ContextWrapper的startActivity方法中,调用了mBase.startActivity,这个不就是装饰着模式的例子吗?实现了注入被装饰者,然后调用被装饰者方法的逻辑
第四步:寻找装饰者类
Activity:Activity继承了ContextWrapper,相当于是装饰者,在Activity内部可以调用startActivity。
至此:Android源码中的装饰着模式寻找完毕。
装饰模式总结
通过上面的学习,我们发现装饰模式其实并不是很复杂,其实就是一种类的封装,然后在此基础上对功能的增强。