OkHttp 源码中设计模式还是值得我学习借鉴的。
OkHttp设计模式
源码分析:http://blog.piasy.com/2016/07/11/Understand-OkHttp/#section-2
这位作者大大,分析很棒(我只是在他的基础上学习扩展下下)
public OkHttpClient() {
this(new Builder());
}
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}
对象创建型模式(Builder模式)
使用Builder模式处理需要很多参数的构造函数,提高代码可读性。(Builder模式的优点)
下面例子比较可以很好理解Builder模式的好处。
本地缓存对象构造对比:
//如果这样构造对象可读性很差,虽然实现了功能
RxCache rxCache = new RxCache(new File(getCacheDir().getPath() + File.separator + "data-wuxiao"),
new DiskConverter(),2*1024*1024,40*1024*1024)
使用Builder模式
RxCache rxCache = new RxCache.Builder()
.diskDir(new File(getCacheDir().getPath() + File.separator + "data-wuxiao"))
.diskConverter(new DiskConverter())
.memory(2*1024*1024)
.disk(40*1024*1024)
.build();
总结:
构建对象时,如果碰到类有很多参数——其中很多参数类型相同而且很多参数可以为空时,我更喜欢Builder模式来完成。如参数数量不多、类型不同实现Builder并体现不出它的优势(传统的构造函数则更加优势)。
OkHttp - Interceptor责任链模式
Interceptor是 OkHttp 核心类,它把网络请求、缓存、透明压缩等功能都统一了起来,每一个功能都是一个 Interceptor,它们再连接成一个 Interceptor.Chain,如链条一般,分工明确,完美完成一次网络请求。
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
责任链其实在Android应用也存在(如:事件传递就是责任链机制)。
那么它在Android中是如何使用?
有时界面上会弹出好几个这种临时显示的窗体或者控件,它们只是为了显示一下,然后需要用户关闭,常常我们希望可以按下返回键将它们关闭。
一般会写如下代码:
//这种也算是责任链的简单体现
if(viewA.isShow()){
viewA.dismiss();
}else if(viewB.isShow()){
viewB.dismiss();
}
.....
如果只有一两个,这么写还可以。但如果情况复杂了的话,这么写,设计上就会很糟糕。在这种情况下使用责任链模式来处理会更优一些。
我们以一个简单例子来证明这种设计模式的好处:
IStatus这个接口用于交互布局的状态(显示或者隐藏):
public interface IStatus<T> {
public boolean onStatus(@NonNull T status);
}
ViewStatus类对IStatus接口进行了初步实现,它是布局交互的核心。它会首先询问自己是否显示(隐藏)布局 ,否则的话会交给下个布局。
public abstract class ViewStatus<T> implements IStatus<T> {
protected IStatus mViewStatus;
protected T view;
/**
* @param mViewStatus 下一个状态对象的接受者
* @param view 下一个view
*/
public ViewStatus(IStatus mViewStatus, T view) {
this.mViewStatus = mViewStatus;
this.view = view;
}
@Override
public boolean onStatus(@NonNull T status) {
boolean isStatus = onStatusImpl(status);
if (!isStatus && mViewStatus != null)
return mViewStatus.onStatus(view);
return isStatus;
}
/**
* @param status
* @return 代表view状态是否显示
*/
protected abstract boolean onStatusImpl(@NonNull T status);
}
隐藏view
public class InVisibleViewStatus extends ViewStatus<View> {
public InVisibleViewStatus(IStatus mViewStatus, View view) {
super(mViewStatus, view);
}
@Override
public boolean onStatusImpl(@NonNull View status) {
View tempView = status;
if (tempView.getVisibility() == View.VISIBLE) {
tempView.setVisibility(View.INVISIBLE);
return true;
}
return false;
}
用于View显示隐藏的Demo
view_1 = findViewById(R.id.view1);
view_2 = findViewById(R.id.view2);
view_3 = findViewById(R.id.view3);
view_4 = findViewById(R.id.view4);
//生成事件处理责任链,startViewStatus为链头,处理顺序由外向内
ViewStatus viewStatus3 = new VisibleViewStatus(null, null);
ViewStatus viewStatus2 = new InVisibleViewStatus(viewStatus3, view_4);
ViewStatus viewStatus1 = new InVisibleViewStatus(viewStatus2, view_3);
startViewStatus = new InVisibleViewStatus(viewStatus1, view_2);
findViewById(R.id.back).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startViewStatus.onStatus(view_1);
}
});
-
演示
责任链模式demo地址:https://github.com/quiet-wuxiao/ResponsibilityChainDemo
总结:责任链模式优点可以对请求者和处理者关系的解耦提高代码的灵活性,如果在上面例子中再添加个view动画的特效,仅仅需要继承ViewStatus进行动画添加就可以,已存在类都可保持不变。责任链模式的最大缺点是对链中布局对象的遍历,如果布局对象太多那么遍历必定会影响性能。