OkHttp 源碼中設(shè)計(jì)模式還是值得我學(xué)習(xí)借鑒的俯逾。
OkHttp設(shè)計(jì)模式
源碼分析:http://blog.piasy.com/2016/07/11/Understand-OkHttp/#section-2
這位作者大大佩抹,分析很棒(我只是在他的基礎(chǔ)上學(xué)習(xí)擴(kuò)展下下)
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;
}
對(duì)象創(chuàng)建型模式(Builder模式)
使用Builder模式處理需要很多參數(shù)的構(gòu)造函數(shù)芯咧,提高代碼可讀性巢音。(Builder模式的優(yōu)點(diǎn))
下面例子比較可以很好理解Builder模式的好處痴奏。
本地緩存對(duì)象構(gòu)造對(duì)比:
//如果這樣構(gòu)造對(duì)象可讀性很差裸违,雖然實(shí)現(xiàn)了功能
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();
總結(jié):
構(gòu)建對(duì)象時(shí)湃鹊,如果碰到類有很多參數(shù)——其中很多參數(shù)類型相同而且很多參數(shù)可以為空時(shí),我更喜歡Builder模式來(lái)完成。如參數(shù)數(shù)量不多后豫、類型不同實(shí)現(xiàn)Builder并體現(xiàn)不出它的優(yōu)勢(shì)(傳統(tǒng)的構(gòu)造函數(shù)則更加優(yōu)勢(shì))悉尾。
OkHttp - Interceptor責(zé)任鏈模式
Interceptor是 OkHttp 核心類,它把網(wǎng)絡(luò)請(qǐng)求挫酿、緩存构眯、透明壓縮等功能都統(tǒng)一了起來(lái),每一個(gè)功能都是一個(gè) Interceptor早龟,它們?cè)龠B接成一個(gè) Interceptor.Chain惫霸,如鏈條一般,分工明確葱弟,完美完成一次網(wǎng)絡(luò)請(qǐng)求壹店。
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);
}
責(zé)任鏈其實(shí)在Android應(yīng)用也存在(如:事件傳遞就是責(zé)任鏈機(jī)制)。
那么它在Android中是如何使用?
有時(shí)界面上會(huì)彈出好幾個(gè)這種臨時(shí)顯示的窗體或者控件芝加,它們只是為了顯示一下硅卢,然后需要用戶關(guān)閉,常常我們希望可以按下返回鍵將它們關(guān)閉妖混。
一般會(huì)寫如下代碼:
//這種也算是責(zé)任鏈的簡(jiǎn)單體現(xiàn)
if(viewA.isShow()){
viewA.dismiss();
}else if(viewB.isShow()){
viewB.dismiss();
}
.....
如果只有一兩個(gè)老赤,這么寫還可以。但如果情況復(fù)雜了的話制市,這么寫抬旺,設(shè)計(jì)上就會(huì)很糟糕。在這種情況下使用責(zé)任鏈模式來(lái)處理會(huì)更優(yōu)一些祥楣。
我們以一個(gè)簡(jiǎn)單例子來(lái)證明這種設(shè)計(jì)模式的好處:
IStatus這個(gè)接口用于交互布局的狀態(tài)(顯示或者隱藏):
public interface IStatus<T> {
public boolean onStatus(@NonNull T status);
}
ViewStatus類對(duì)IStatus接口進(jìn)行了初步實(shí)現(xiàn)开财,它是布局交互的核心。它會(huì)首先詢問(wèn)自己是否顯示(隱藏)布局 误褪,否則的話會(huì)交給下個(gè)布局责鳍。
public abstract class ViewStatus<T> implements IStatus<T> {
protected IStatus mViewStatus;
protected T view;
/**
* @param mViewStatus 下一個(gè)狀態(tài)對(duì)象的接受者
* @param view 下一個(gè)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狀態(tài)是否顯示
*/
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);
//生成事件處理責(zé)任鏈,startViewStatus為鏈頭,處理順序由外向內(nèi)
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);
}
});
-
演示
責(zé)任鏈模式demo地址:https://github.com/quiet-wuxiao/ResponsibilityChainDemo
總結(jié):責(zé)任鏈模式優(yōu)點(diǎn)可以對(duì)請(qǐng)求者和處理者關(guān)系的解耦提高代碼的靈活性兽间,如果在上面例子中再添加個(gè)view動(dòng)畫的特效历葛,僅僅需要繼承ViewStatus進(jìn)行動(dòng)畫添加就可以,已存在類都可保持不變嘀略。責(zé)任鏈模式的最大缺點(diǎn)是對(duì)鏈中布局對(duì)象的遍歷恤溶,如果布局對(duì)象太多那么遍歷必定會(huì)影響性能。