什么是模版设计模式
主要是解决一类问题,什么问题呢?
比如某个功能类的一个功能模块,这个功能模块(我们暂且叫做Func1)抽象来看大体流程是一样的,分1,2,3步,只是其中有细小的差异
那么我们可以这么搞,把这个类定义成抽象类,Func1定义成具体方法,而1,2,3这几步,我们把它定义成抽象方法,这样当前类的子类在实现它的Func1方法时,既遵循了1,2,3的步骤,又在实现1,2,3抽象方法时个性化了它自己要处理的内容
举例子吧,简单地找个网上的例子来,汽车开启(start)到结束(stop)一整个流程(excet)分start->stop两步,但是每个车型的开启和发动的细节是不一样的
先来个抽象的汽车类
public abstract class CarModel {
/**
* 汽车启动
*/
protected abstract void start();
/**
* 停车
*/
protected abstract void stop();
/**
* 用户并不需要关注你的车怎么启动或者停下来的,可以开可以停就可以啦
*/
final public void excet(){
this.start();
this.stop();
}
}
2.造个大众车,再造个奥迪
public class Wcar extends CarModel{
@Override
protected void start() {
System.out.println("大众车启动 。。。。。。。。突突突");
}
@Override
protected void stop() {
System.out.println("大众车停车。。。。。。。。。");
}
}
public class Ocar extends CarModel{
@Override
protected void start() {
System.out.println("奥迪 无匙启动 突突突");
}
@Override
protected void stop() {
System.out.println("奥迪 停车 ");
}
}
好了,这下可以试试这两辆车了
public class Client {
public static void main(String[] args) {
CarModel wcar=new Wcar();//家里的第一辆车,作为用户的我们并不需要关注车怎么启动的.子类变量变为父类。多态
wcar.excet();
//突然家里需要第二辆车了 奥迪 我们也不需要关注他怎么生产启动的
CarModel ocar=new Ocar();
ocar.excet();
}
}
如上代码,大众和奥迪实现了汽车类,这样保证了他们一整个操作流程excet是一样的,然后各自实现了start()和stop()方法
Retrofit中哪里用到了模版模式
在retrofit源码中用到的设计模式(一)代理模式的最后,我们提到了
// 解析参数注解
ServiceMethod serviceMethod = loadServiceMethod(method);
这句话开始,要解析注解了
我们想,Retrofit在定义Api类的时候,方法的入参里有很多诸如@Query的注解,解析这些注解肯定大同小异,我们的沃顿大神这时候想到了模版设计模式,我们简化下源码看看
回顾上文代码,我们说Retrofit使用了动态代理,代理了我们定义的网络接口类ApiService,通过Retrofit.create,代码如下
public class Retrofit {
final String baseUrl;
final okhttp3.Call.Factory callFactory;
private Map<Method,ServiceMethod> serviceMethodMapCache = new ConcurrentHashMap<>();
public Retrofit(Builder builder) {
this.baseUrl = builder.baseUrl;
this.callFactory = builder.callFactory;
}
public <T> T create(Class<T> service) {
// 检验,是不是一个接口 ,不能让他继承子接口
// 重点
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 每执行一个方法都会来这里
// 判断是不是 Object 的方法 ?
if(method.getDeclaringClass() == Object.class){
return method.invoke(this,args);
}
// 解析参数注解
ServiceMethod serviceMethod = loadServiceMethod(method);
// 2. 封装 OkHttpCall
OkHttpCall okHttpCall = new OkHttpCall(serviceMethod,args);
// 返回代理对象的执行结果,此处是OkHttpCall
return okHttpCall;
}
});
}
我们看看 loadServiceMethod发生了什么?Retrofit对解析出来的参数做了个缓存,缓存找不到,那么把Method传入去解析注解
private ServiceMethod loadServiceMethod(Method method) {
ServiceMethod serviceMethod = serviceMethodMapCache.get(method);
if(serviceMethod == null){
serviceMethod = new ServiceMethod.Builder(this,method).build();
serviceMethodMapCache.put(method,serviceMethod);
}
return serviceMethod;
}
接着看看
ServiceMethod.Builder(this,method).build();
public static class Builder {
final Retrofit retrofit;
final Method method;
final Annotation[] methodAnnotations;
String httpMethod;
String relativeUrl;
Annotation[][] parameterAnnotations;
final ParameterHandler<?>[] parameterHandlers;
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 方法上面的注解
methodAnnotations = method.getAnnotations();
// 二维数组
// 参数注解
parameterAnnotations = method.getParameterAnnotations();
parameterHandlers = new ParameterHandler[parameterAnnotations.length];
}
// 解析注解
public ServiceMethod build() {
// 解析,OkHttp 请求的时候 ,url = baseUrl + relativeUrl,method
for (Annotation methodAnnotation : methodAnnotations) {
// 解析 POST GET
parseAnnotationMethod(methodAnnotation);
}
// 解析参数注解
int count = parameterHandlers.length;
for (int i = 0; i < count; i++) {
Annotation parameter = parameterAnnotations[i][0];
// Query 等等
if (parameter instanceof Query) {
// 一个一个封装成 ParameterHandler ,不同的参数注解选择不同的策略
parameterHandlers[i] = new ParameterHandler.Query<>(((Query) parameter).value());
}
}
return new ServiceMethod(this);
}
private void parseAnnotationMethod(Annotation methodAnnotation) {
// value ,请求方法
if (methodAnnotation instanceof GET) {
parseMethodAndPath("GET", ((GET) methodAnnotation).value());
} else if (methodAnnotation instanceof POST) {
parseMethodAndPath("POST", ((POST) methodAnnotation).value());
}
// 还有一大堆解析 if else
}
private void parseMethodAndPath(String method, String value) {
this.httpMethod = method;
this.relativeUrl = value;
}
请关注中间的一段代码:
// 解析注解
public ServiceMethod build() {
......
// 解析参数注解
int count = parameterHandlers.length;
for (int i = 0; i < count; i++) {
Annotation parameter = parameterAnnotations[i][0];
// Query 等等
if (parameter instanceof Query) {
// 一个一个封装成 ParameterHandler ,不同的参数注解选择不同的策略
parameterHandlers[i] = new ParameterHandler.Query<>(((Query) parameter).value());
}
}
......
return new ServiceMethod(this);
}
在解析不同注解时,Retrofit定义了不同的注解解释类,但是,注解解释类都有一个共同的接口,ParameterHandler
public interface ParameterHandler<T> {
public void apply(RequestBuilder requestBuilder,T value);
// 很多策略,Query ,Part , QueryMap ,Field 等等
class Query<T> implements ParameterHandler<T>{
private String key; // 保存 就是参数的 key = userName ,password
public Query(String key){
this.key = key;
}
@Override
public void apply(RequestBuilder requestBuilder,T value) {
// 添加到request中 // value -> String 要经过一个工厂
requestBuilder.addQueryName(key,value.toString());
}
}
// 还有一些其他
}
即使不看后面的执行时的代码,我们也知道,在发起请求前,Retrofit肯定通过遍历parameterHandlers执行 public void apply(RequestBuilder requestBuilder,T value);方法,拼接了传入的各自注解参数
这个位置就是Retrofit巧妙使用模版解释注解的地方