上篇博客 http://blog.csdn.net/zx_android/article/details/79273797,通过换汤不换药的方式把客户的switch case转移到了context中,我始终不是太满意,后来终于找到一个大神的一篇文章:设计模式学习之策略模式
得到了一个比较满意的解决。
(想用纯策略模式来完全解决 if else if switch case这种需求,是做不到的,或许策略模式根本不能这么用,最近看到一个开源框架,作者使用策略模式+适配器模式完美结合,前提是在使用之前要在Application中选择自己的适配器,如果两个适配器进行选一使用的时候,是不是也要进行if else if switch case的判断了呢?)
即:
https://github.com/orhanobut/logger ,一个日志打印框架
此框架相关可以参照:
http://blog.csdn.net/u013277740/article/details/79284384
废话不多说,下面升级一下我们的策略模式实现retrofit公共参数:
主要更改的是把ParamsContext类中的Switch case 去掉,换一种方式。
switch (request.method()) {
case GET:
iRequestParam = new GetRequestParams();
break;
case POST:
iRequestParam = new PostRequestParams();
break;
(不然新增一个新的策略,是不是又要加个case?)
为了不加case,我们来试试反射:
1、注解类:
//适用于类上面的注解
@Target(ElementType.TYPE)
//运行时注解
@Retention(RetentionPolicy.RUNTIME)
public @interface Method {
//返回String,默认GET
String value() default "GET";
}
2、具体实现类加上注解
什么都不改,就类上面加个注解即可:@Method(“GET”)
@Method("GET")
public class GetRequestParams implements IRequestParam {
@Override
public Request getRequest(Request request, Context context) {
//添加公共参数
HttpUrl modifiedUrl = request.url().newBuilder()
.addQueryParameter(CLIENT, AppTools.getClient(context))
.addQueryParameter(VERSION, AppTools.getAppVersion(context))
.addQueryParameter(TOKEN, AppTools.getToken(context))
.build();
return request.newBuilder().url(modifiedUrl).build();
}
}
POST同上
@Method("POST")
public class PostRequestParams implements IRequestParam {
@Override
public Request getRequest(Request request, Context context) {
if (request.body() instanceof FormBody) {
FormBody.Builder bodyBuilder = new FormBody.Builder();
FormBody formBody = (FormBody) request.body();
for (int i = 0; i < formBody.size(); i++) {
bodyBuilder.addEncoded(formBody.encodedName(i), formBody.encodedValue(i));
}
formBody = bodyBuilder.add(CLIENT, AppTools.getClient(context))
.addEncoded(VERSION, AppTools.getAppVersion(context))
.addEncoded(TOKEN, AppTools.getToken(context))
.build();
request = request.newBuilder().post(formBody).build();
}
return request;
}
}
好了,这些做完之后,就改修改关键地方了 ParamsContext,
一句话:拿到IRequestParam的所有实现类 返回即可
具体代码如下:
public class ParamsContext {
public static final String GET = "GET";
public static final String POST = "POST";
private Context context;
private Request request;
//--------------------------------注解相关-----------------------------------
private List<Class<? extends IRequestParam>> requestParamList;
public ParamsContext(Request request, Context context) {
this.context = context;
this.request = request;
init();
}
public Request getInRequest() {
//选择策略进行处理
IRequestParam iRequestParam = chooseRequest(request.method());
return iRequestParam.getRequest(request, context);
}
//------------------------------反射获取注解-----------------------------------
private void init() {
requestParamList = new ArrayList<>();
try {
String packageName = getClass().getPackage().getName();
Class<?> getRequestParams = Class.forName(packageName + ".GetRequestParams");
Class<?> postRequestParams = Class.forName(packageName + ".PostRequestParams");
List<Class<?>> classList = new ArrayList<>();
classList.add(getRequestParams);
classList.add(postRequestParams);
for (int i = 0; i < classList.size(); i++) {
Class<?> clazz = classList.get(i);
//判断clazz是否是IRequestParam的实现类
if (IRequestParam.class.isAssignableFrom(clazz)) {
requestParamList.add((Class<? extends IRequestParam>) clazz);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//根据返回的method产生相应的方法
public IRequestParam chooseRequest(String requestMethod) {
//在策略列表中查找策略
for (Class<? extends IRequestParam> clazz : requestParamList) {
//获取该策略的注解
Method method = clazz.getAnnotation(Method.class);
if (requestMethod.equals(method.value())) {
try {
return clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("策略获得失败");
}
}
}
throw new RuntimeException("策略获得失败");
}
}
客户端使用不变:
public Interceptor initQuery(final Context context) {
Interceptor addQueryParameterInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
request = new ParamsContext(request, context).getInRequest();
return chain.proceed(request);
}
};
return addQueryParameterInterceptor;
}
至此,修改就结束了,此时如果我想添加一个新的策略(update、delete等..),只需要加一个带有注解的策略即可
源码:https://github.com/MrXiong/ZxRetrofit2.0
———————————————–分割线—————————————-
这里有个问题,设计模式学习之策略模式 这篇文章里面获取包下面的类是通过getClass().getClassLoader().getResource获取的,我这里是通过 Class.forName方法获取的,就是事先需要知道IRequestParam接口的实现类,那么如果新增一个新策略,这个势必也要新增一个。
那篇文章的获取包下面所有类是这样写的:
private File[] getResources() {
try {
File file = new File(classLoader.getResource(CAL_PRICE_PACKAGE.replace(".", "/")).toURI());
return file.listFiles(new FileFilter() {
public boolean accept(File pathname) {
if (pathname.getName().endsWith(".class")) {//我们只扫描class文件
return true;
}
return false;
}
});
} catch (URISyntaxException e) {
throw new RuntimeException("未找到策略资源");
}
}
可是我在Android Sudio中使用怎么获取到的getResource始终是空的,后来我想不就是找.class文件么,Android Studio编译后的.class文件不就在/app/build/intermediates/classes 这里么,我就把路径换了一下:
private File[] getResources() {
try {
String classPath = "../app/build/intermediates/classes/debug/com/zx/rxjava/policy";
URL resource = getClass().getClassLoader().getResource(classPath);
Logs.d(resource +"");
URI uri = resource.toURI();
File file = new File(classPath);
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.getName().endsWith(".class")) {//我们只扫描class文件
return true;
}
return false;
}
});
return files;
} catch (Exception e) {
throw new RuntimeException("未找到策略资源");
}
}
可是仍然获取不到值,各位大佬知道问题的请告知我哦,O(∩_∩)O谢谢