项目架构演变--从门面模式到代理模式

我们使用项目演进的方式来看看怎么从最开始原始的代码书写,这种方式代码严重耦合,没有复用性可言,如果我们想加一些统一的请求参数需要在每个地方都修改一遍,工作量是巨大的。那么我们自然就想到了如何在此基础上进行一定的封装,让用到的地方进行统一的请求,而不用重复的代码书写多遍。再到后面我们有更多的切换网络库的需求的话,是如何使用代理模式做到可以随意切换网络库。这三个层次,来看看较好的写法的演进过程。为了简便,我们使用volley作为网络请求的三方库。

项目代码在这里:https://github.com/buder-cp/DesignPattern/tree/master/FacadeToAgentMode

版本一:

最开始我们写网络请求如果没有进行过封装,就是下面这个样子:

@Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.http_request) {
            StringRequest stringRequest = new StringRequest(Request.Method.GET,
                    URL, new Response.Listener() {
                @Override
                public void onResponse(String response) {
                    try {
                        JSONObject obj = new JSONObject(response);
                        String source = obj.getString("source");
                        Toast.makeText(MainActivity.this, source, Toast.LENGTH_SHORT).show();

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {

                }
            });

            mQueue.add(stringRequest);
        }
    }

在需要使用到网络请求的地方,直接使用最原始的请求方式,这种方式的缺点是非常明显的,第一:比如我工程中有100个地方需要网络请求,那么StringRequest请求的原始写法需要写一百次,如果某天需要统一添加请求消息头信息了,还要在100个地方逐个修改;第二:网络请求逻辑和UI耦合,我们需要尽量做到逻辑和UI分离,这个倒好,直接混合到一起去了,如果业务复杂的话,一个文件中的代码量会爆棚。缺点这么多,那么我们自然而然就想到了,需要写一个统一的网络请求类,来管理网络请求那么下面就是我们的2.0,门面模式版本:

版本二:门面模式使用

public class FacadeNetWork {

    public interface Callback {
        void onSuccess(T respone);
        void onFailed(String failed);
    }

    private static RequestQueue mQueue;
    private static FacadeNetWork mInstance;
    private Context mContext;

    private FacadeNetWork(Context context) {
        mContext = context;
        mQueue = Volley.newRequestQueue(context);
    }

    public static FacadeNetWork getInstance(Context context) {
        if (mInstance == null) {
            synchronized (FacadeNetWork.class) {
                if (mInstance == null) {
                    mInstance = new FacadeNetWork(context);
                }
            }
        }
        return mInstance;
    }
    public void get(final String url, final Callback callback) {
        StringRequest stringRequest = new StringRequest(Request.Method.GET,
                url, new Response.Listener() {
            @Override
            public void onResponse(String response) {
                try {
                    JSONObject obj = new JSONObject(response);
                    String source = obj.getString("source");
                    callback.onSuccess(source);

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                callback.onFailed(error.toString());
            }
        });

        mQueue.add(stringRequest);
    }
}

使用单例对外提供网络请求的服务调用,下面的get、post等等网络请求我们统一写出来,那么我们的调用就会很方便,如下:

FacadeNetWork facadeNetWork = FacadeNetWork.getInstance(this);
            facadeNetWork.get(URL, new FacadeNetWork.Callback() {
                @Override
                public void onSuccess(Object respone) {
                    Toast.makeText(MainActivity.this, respone.toString(), Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onFailed(String failed) {

                }
            });

实际项目中,我们大部分都是这么做的,但是还是不够好,如果某一天我们的网络请求库变了,需要使用Retrofit的话,此时我们就需要修改我们的网络请求的管理类FacadeNetWork里面的请求代码,这不符合关闭修改原则,因为我们写好的类是不允许改变的,需要改变的原因是我们的扩展做的不够好,那么我们使用代理模式来增强我们这个架构的可扩展性,

版本三:使用代理模式(代理就是个二道贩子,左手进右手出,我们找代理提供服务,代理去找真实可提供服务的类,因此我们要知道我们需要的服务名称,这个服务名称就是需要代理和服务类去实现的统一的接口,步骤如下)

步骤一:代理类和真实实现类的服务,这俩名字肯定是一样的,是事先约定好的服务名称,这里我们用接口来表示,例如需要get请求服务:

代理类和真实类的统一服务名称:

public interface IHttp {
    void get(String url, ICallBack callBack);
}

步骤二:真实提供服务类肯定需要实现这项服务,我们可以有多个真实实现服务的类,这里我们用Volley和OKHttp举例:

volley实现类:

public class VolleyModel implements IHttp{

    private static RequestQueue mQueue;
    private static VolleyModel mInstance;
    private Context mContext;

    private VolleyModel(Context context) {
        mContext = context;
        mQueue = Volley.newRequestQueue(context);
    }

    public static VolleyModel getInstance(Context context) {
        if (mInstance == null) {
            synchronized (VolleyModel.class) {
                if (mInstance == null) {
                    mInstance = new VolleyModel(context);
                }
            }
        }
        return mInstance;
    }

    @Override
    public void get(String url, final ICallBack callBack) {
        StringRequest stringRequest = new StringRequest(Request.Method.GET,
                url, new Response.Listener() {
            @Override
            public void onResponse(String response) {
                try {
                    JSONObject obj = new JSONObject(response);
                    String source = obj.getString("source");
                    callBack.onSuccess(source);

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                callBack.onFailed(error.toString());
            }
        });

        mQueue.add(stringRequest);
    }
}

OKHttp实现类:

public class OkHttpModel implements IHttp{

    private static RequestQueue mQueue;
    private static OkHttpModel mInstance;
    private Context mContext;

    private OkHttpModel(Context context) {
        mContext = context;
        mQueue = Volley.newRequestQueue(context);
    }


    @Override
    public void get(String url, final ICallBack callBack) {
        StringRequest stringRequest = new StringRequest(Request.Method.GET,
                url, new Response.Listener() {
            @Override
            public void onResponse(String response) {
                try {
                    JSONObject obj = new JSONObject(response);
                    String source = obj.getString("source");
                    callBack.onSuccess(source);

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                callBack.onFailed(error.toString());
            }
        });

        mQueue.add(stringRequest);
    }
}

步骤三:我们需要找的代理,这个二道贩子,他为什么需要实现这个接口呢,我们说了,代理就是一个转发,我们提前知道我们自己需要的是什么服务,这个服务在代理和实现类中的名字是一样的

public class HttpProxy implements IHttp {

    private static IHttp mHttp = null;

    private static HttpProxy mInstance;

    private HttpProxy() {
        mInstance = this;
    }

    public static HttpProxy obtain() {
        if (mInstance == null) {
            synchronized (OkHttpModel.class) {
                if (mInstance == null) {
                    mInstance = new HttpProxy();
                }
            }
        }
        return mInstance;
    }

    public static void init(IHttp http) {
        mHttp = http;
    }

    /**
     * 代理的扩展属性和方法增强性
     * @param url
     * @param callBack
     */
    @Override
    public void get(String url, ICallBack callBack) {
        /**
         * 代理类的作用:
         * 1.可以在调用真正服务的类之前,做一些自己额外的任务,例如收取手续费,请求重定向等等;
         * 代理类可以实现拦截方法,修改原方法的参数和返回值,满足了代理自身需求和目的,也就
         * 是代理的方法增强性。
         * 2.内部对象因为某个原因换了个名或者换了个方法字段等等,那对访问者来说一点不影响,
         * 因为他拿到的只是代理类而已,从而使该访问对象具有高扩展性
         */
        mHttp.get(url, callBack);
    }
}

注意这里使用了多态,谁注册的init()函数对象,我们就使用哪个网络框架服务,切换网络框架如下:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        HttpProxy.init(VolleyModel.getInstance(getApplicationContext()));
//        HttpProxy.init(OkHttpModel.getInstance(getApplicationContext()));
    }
}

 

项目代码:https://github.com/buder-cp/DesignPattern/tree/master/FacadeToAgentMode

你可能感兴趣的:(Java设计模式)