策略模式(注解版)实现 retrofit 的get和post请求的公共参数(二)

上篇博客 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谢谢

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哆啦A梦z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值