写完代码过后需求更改你需要改很多个地方的代码,证明你的代码是有问题的。
simple1
简单的在Activity中访问网络然后解析数据,这种方式是我们大家刚开始接触代码时写出来的。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Map<String, Object> params = new HashMap<>();
params.put("iid", 201321092107L);
params.put("password", "woshihaizeiwang");
final Request request = new Request.Builder().url("www.cailei.com").build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//数据失败
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("response", response.body() + "");
final String resultJson = response.body().string();
//1.Json数据解析 2.显示列表数据 3.缓存数据
}
});
simple2
第二步,将一些公共方法封装成工具类,每一次调用网络访问的时候就调用HttpUtils的静态方法;
public class HttpUtils {
public HttpUtils(){
}
public static void get(Context context, String baseUrl, Map<String,Object> params, final Callback callback){
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
//公共参数
params.put("iid", 201321092107L);
params.put("password", "woshihaizeiwang");
final Request request = new Request.Builder().url(baseUrl).build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//数据失败
callback.onFailure(call,e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// Log.e("response", response.body() + "");
// final String resultJson = response.body().string();
//1.Json数据解析 2.显示列表数据 3.缓存数据
callback.onResponse(call,response);
}
});
}
simple3
可以看见simple2中网络访问没有加入缓存,只是将一些公共的网络逻辑写成了一个工具类,simple3加入了缓存,然后利用反射将okhttp返回的结果处理成了Bean类。
public static <T> void get(Context context, String baseUrl, Map<String, Object> params, final
HttpCallBack<T> callBack, final boolean cache) {
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
//公共参数
params.put("iid", 201321092107L);
params.put("password", "woshihaizeiwang");
String joinUrl = baseUrl + parseParams(params);
final String cacheJson = (String) SharePreferencesUtils.getInstance().getParam("joinUrl",
"");
if (cache && !TextUtils.isEmpty(cacheJson)) {
Gson gson = new Gson();
T resultBean = (T) gson.fromJson(cacheJson, getResultBeanClass(callBack));
callBack.onSuccess(resultBean);
}
final Request request = new Request.Builder().url(baseUrl).build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//数据失败
callBack.onFail(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// Log.e("response", response.body() + "");
final String resultJson = response.body().string();
//1.Json数据解析 2.显示列表数据 3.缓存数据
Gson gson = new Gson();
T objectJson = (T) getResultBeanClass(callBack);
callBack.onSuccess(objectJson);
if (cache) {
SharePreferencesUtils.getInstance().saveParam("joinurl", resultJson);
}
}
});
}
private static String parseParams(Map<String, Object> params) {
return "sb";
}
public static <T> Class<?> getResultBeanClass(HttpCallBack<T> callBack) {
Type type = callBack.getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) type).getActualTypeArguments();
return (Class<?>) params[0];
}
单一职责原则
就一个类而言,应该仅有一个引起它变化的原因。简单来说,一个类中应该是一组相关性很高的函数,数据的封装。
simple3中的请求和缓存全都写到了一堆,根据单一职责的原则我们来更改一下代码:
新建一个类:HttpRequest.java
public class OkhttpRequest {
private SpHttpCache spHttpCache;
public OkhttpRequest(){
spHttpCache=new SpHttpCache();
}
public <T> void get(Context context, String baseUrl, Map<String, Object> params, final HttpCallBack<T> callBack, final boolean cache) {
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
//公共参数
params.put("iid", 201321092107L);
params.put("password", "woshihaizeiwang");
final String joinUrl = baseUrl + parseParams(params);
final String cacheJson = spHttpCache.getCache(joinUrl);
if (cache && !TextUtils.isEmpty(cacheJson)) {
Gson gson = new Gson();
T resultBean = (T) gson.fromJson(cacheJson, getResultBeanClass(callBack));
callBack.onSuccess(resultBean);
}
final Request request = new Request.Builder().url(baseUrl).build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//数据失败
callBack.onFail(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// Log.e("response", response.body() + "");
final String resultJson = response.body().string();
//1.Json数据解析 2.显示列表数据 3.缓存数据
Gson gson = new Gson();
T objectJson = (T) getResultBeanClass(callBack);
callBack.onSuccess(objectJson);
if (cache) {
spHttpCache.saveCache(joinUrl,resultJson);
}
}
});
}
private static String parseParams(Map<String, Object> params) {
return "sb";
}
public static <T> Class<?> getResultBeanClass(HttpCallBack<T> callBack) {
Type type = callBack.getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) type).getActualTypeArguments();
return (Class<?>) params[0];
}
可以发现这个类中依赖着另外一个类SpHttpCache.java(这个类的作用就是进行sp缓存):
public class SpHttpCache {
public void saveCache(String url, String json) {
SharePreferencesUtils.getInstance().saveParam(url, json);
}
public String getCache(String url) {
return (String) SharePreferencesUtils.getInstance().getObject(url);
}
}
我们已经把网络请求和缓存都各自封装成类了,保证了单一职责
HttpUtils.java
public class HttpUtils {
private OkhttpRequest okhttpRequest;
public HttpUtils() {
okhttpRequest=new OkhttpRequest();
}
public <T> void get(Context context, String baseUrl, Map<String, Object> params, final HttpCallBack<T> callBack, final boolean cache) {
okhttpRequest.get(context,baseUrl,params,callBack,true);
}
我们每次访问网络直接调用HttpUtils的get方法就行了。但是有没有发现如果我们在get方法里面继续加一些参数,这样这get方法就会很长很长,用的人也要去搞清楚这个方法里面的参数到底是干什么的,万一传错了值呢?这时候我们可以采用链式调用的方式改进代码
public class HttpUtils {
private OkhttpRequest okhttpRequest;
private final int TYPE_POST = 0x0011, TYPE_GET = 0x0022;
private String mUrl;
private Context mContext;
private Map<String, Object> mParams;
private HttpUtils(Context context) {
okhttpRequest = new OkhttpRequest();
mParams = new HashMap<>();
this.mContext = context;
}
public static HttpUtils with(Context context) {
return new HttpUtils(context);
}
public HttpUtils param(String key, Object value) {
mParams.put(key, value);
return this;
}
public HttpUtils url(String url) {
this.mUrl = url;
return this;
}
public HttpUtils cache(boolean cache) {
// TODO
return this;
}
public <T> void get(final HttpCallBack<T> callback) {
okhttpRequest.get(mContext, mUrl, mParams, callback, true);
}
问题,当我们要用xutils,okhttp,Retrofit…的时候怎么切换第三方网络框架?
开闭原则
定义:软件中的对象(类,模块,函数)应该对于扩展是开放的,对于修改是关闭的。
什么意思?比如说上面你要换一个网络框架的时候,你是不是得去吧HttpUtils里面的OkhttpRequest引擎改成其他的比如Xutils的引擎。我们尽量的让用户少一点的知道了解我们的代码,我们对外就开放一个HttPUtils类,用户传一些参数就能访问网络获取数据。在不改变这个类的代码的情况下怎么去更换网络引擎。
private static IHttpRequest httpRequest;
private final int TYPE_POST = 0x0011, TYPE_GET = 0x0022;
private String mUrl;
private Context mContext;
private Map<String, Object> mParams;
private HttpUtils(Context context) {
okhttpRequest = new OkhttpRequest();
mParams = new HashMap<>();
this.mContext = context;
}
public static HttpUtils with(Context context) {
return new HttpUtils(context);
}
public HttpUtils param(String key, Object value) {
mParams.put(key, value);
return this;
}
public HttpUtils url(String url) {
this.mUrl = url;
return this;
}
public HttpUtils cache(boolean cache) {
// TODO
return this;
}
public <T> void get(final HttpCallBack<T> callback) {
httpRequest.get(mContext, mUrl, mParams, callback, true);
}
public static void initHttpRequest(XutilsHttpRequest xutilsHttpRequest) {
this.httpRequest = xutilsHttpRequest;
}
BaseAplication.java:
public class BaseAplication extends Application {
@Override
public void onCreate() {
super.onCreate();
HttpUtils.initHttpRequest(new XutilsHttpRequest());
}
}
里斯替换原则
定义:只要父类能出现的地方子类就可以出现,主要体现就是实现和继承,上面的BaseAplication的initHttpRequest中的接口参数是父类,但是传进去的是实现了接口的子类。
依赖倒置原则
定义:指代了一种特定的解耦方式,高层模块不依赖低层次模块的细节,说白了高层次就是不依赖细节而是依赖抽象。比如HttpUtils中的okhttpRequest就是一个细节,是底层次的。后来的iHttpRequest就是抽象的,所以我们依赖的是iHttpRequest.
接口隔离原则
定义:将接口拆分,类似于单一原则,就是接口里面的功能是一种类型的不能有其他的类型
上面5个原则都跟接口和抽象有关(面向接口和面向抽象)
迪米特原则(最少知识原则)
一个对象应该对其他对象有最少的了解,就像用户调用HttpUtils传一些参数就可以了,不需要了解内部实现。