我们使用项目演进的方式来看看怎么从最开始原始的代码书写,这种方式代码严重耦合,没有复用性可言,如果我们想加一些统一的请求参数需要在每个地方都修改一遍,工作量是巨大的。那么我们自然就想到了如何在此基础上进行一定的封装,让用到的地方进行统一的请求,而不用重复的代码书写多遍。再到后面我们有更多的切换网络库的需求的话,是如何使用代理模式做到可以随意切换网络库。这三个层次,来看看较好的写法的演进过程。为了简便,我们使用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里面的请求代码,这不符合关闭修改原则,因为我们写好的类是不允许改变的,需要改变的原因是我们的扩展做的不够好,那么我们使用代理模式来增强我们这个架构的可扩展性,
代理类和真实类的统一服务名称:
public interface IHttp {
void get(String url, ICallBack callBack);
}
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