前言
當(dāng)自己的編碼時(shí)間久了之后,會(huì)發(fā)現(xiàn)優(yōu)秀的代碼,往往是遵循合理的設(shè)計(jì)模式進(jìn)行開發(fā)的,這些代碼具備高內(nèi)聚、低耦合的特性,能夠在隨時(shí)變化的需求中,保持穩(wěn)定性、靈活性。
本文,是在 Android 代碼中去尋找「設(shè)計(jì)模式」的影子,并不會(huì)很詳細(xì)地展開各個(gè)模式的定義與應(yīng)用。開始,盤它!
(篇幅有限且網(wǎng)上優(yōu)秀的書籍多,所以不要想著在這一篇文章弄清楚它們。注:本人水平有限,不對(duì)的地方,還請(qǐng)指出修正)。
一、單例模式
記得曾經(jīng)筆試時(shí)就考過寫出單例模式的實(shí)現(xiàn)方式:1、懶漢式(線程安全);2、餓漢式(DCL);3、靜態(tài)內(nèi)部類;4、枚舉實(shí)現(xiàn)(最佳實(shí)現(xiàn))。
當(dāng)某個(gè)對(duì)象的創(chuàng)建是比較耗時(shí)的,如果頻繁的創(chuàng)建與銷毀的話,對(duì)性能影響又大,既然沒有好的辦法優(yōu)化,那就在內(nèi)存中持有這個(gè)對(duì)象的唯一實(shí)例,減少內(nèi)存占用。
值得注意的是:1、單例對(duì)象創(chuàng)建的線程安全問題;2、Android 中創(chuàng)建單例時(shí),如果持有 Context 容易導(dǎo)致內(nèi)存泄露,盡量使用 Application Context。
例如 Glide、ImageLoader 圖片加載框架,正是采用單例模式,來獲取實(shí)例對(duì)象的。
1、Glide.with(context).load(imageUrl).into(imageView);
2、ImageLoader.getInstance().displayImage(imageUrl,imageView);
二、Builder 模式
構(gòu)建者模式把一個(gè)對(duì)象的創(chuàng)建與表示分離開了,也就是說構(gòu)建的過程不同,會(huì)生產(chǎn)出不同的對(duì)象出來。同時(shí) Builder 類,把具體產(chǎn)品的創(chuàng)建細(xì)節(jié)隱藏了,使得我們不用關(guān)注產(chǎn)品具體是怎么實(shí)現(xiàn)的。例如:我們無需關(guān)注調(diào)用方法的順序,因?yàn)?Builder 類已經(jīng)封裝好了調(diào)用的順序了。還有這種鏈?zhǔn)秸{(diào)用寫起來真的很爽!
最常見的就是我們 Android 里面的對(duì)話框的創(chuàng)建過程了,我們通過 AlertDialog.Builder() 構(gòu)建的過程中,有沒有設(shè)置按鈕、標(biāo)題、提示等,其實(shí)創(chuàng)建出來的對(duì)話框風(fēng)格是不一樣的。
1、new AlertDialog.Builder()
.setTitle("title")
.setMessage("message")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// do something
}
}).create();
2、new StringBuilder().append("A").append("B").append("C").toString();
復(fù)制代碼這里介紹一個(gè) Android Studio 的插件 —— Builder Generator,這個(gè)插件可以省去手寫 Builder 的煩惱。
三、工廠模式
有以下幾種:
1. 簡(jiǎn)單工廠:含靜態(tài)方法,也叫靜態(tài)工廠,多用 if...else 來做分支,去創(chuàng)建各個(gè)實(shí)例,方法內(nèi)部如果創(chuàng)建的對(duì)象多的,會(huì)略顯臃腫
2. 工廠模式:含抽象工廠、具體工廠、抽象產(chǎn)品、具體產(chǎn)品之分,符合“開閉原則”
3. 抽象工廠模式:與工廠模式的區(qū)別,工廠模式創(chuàng)建單一產(chǎn)品,抽象工廠能創(chuàng)建多種產(chǎn)品,符合“開閉原則”
工廠類封裝好類的實(shí)例化過程,隱藏了對(duì)象實(shí)例化的具體參數(shù),只需傳入要?jiǎng)?chuàng)建類的唯一標(biāo)識(shí),工廠類就能創(chuàng)建出指定的類。換句話說:我只告訴工廠我要什么,工廠只負(fù)責(zé)生產(chǎn),我負(fù)責(zé)使用,具體工廠怎么生產(chǎn),我就不管啦~
public class ConcreteFactory extends Factory {
public <T extends Product> T createProduct(Class<T> c){
Product product=null;
try {
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//異常處理
}
return (T)product;
}
}
如 Retrofit 可添加 Gson 轉(zhuǎn)換(這里體現(xiàn)了 Builder 模式 和工廠模式)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
四、策略模式
將算法單獨(dú)封裝起來,使之替換時(shí),互不影響。
之前看過一篇文章說怎么消除項(xiàng)目代碼中的 if...else ,運(yùn)用策略模式,將每個(gè) if...else 里面的方法各自封裝,來解決因?yàn)榇罅康?if...else 導(dǎo)致的類臃腫。
例如:android 中的設(shè)置動(dòng)畫的插值器,替換不同插值器,各不影響,而且效果不同
Animation animation = new AlphaAnimation(1,0);
animation.setInterpolator(new AccelerateDecelerateInterpolator());
imageView.setAnimation(animation);
animation.start();
五、模版模式
在抽象類中,定義模版(抽象)方法,并在子類做具體的實(shí)現(xiàn)。其實(shí)就是我們經(jīng)常用的 BaseActivity 、BaseFragment 那套東西,show code~
在 BaseActivity 里面保證模版方法,按照順序執(zhí)行,同時(shí)子類必須實(shí)現(xiàn)父類定義的抽象方法,提高了復(fù)用性以及擴(kuò)展性。
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 1、獲取布局id
setContentView(getLayoutId());
// 2、初始化 view
initView();
// 3、初始化數(shù)據(jù)
initData();
}
public abstract int getLayoutId();
public abstract void initView();
public abstract void initData();
}
五、適配器模式
適配器模式,可以解決接口不兼容的問題,使得本不兼容的接口一起工作。
舉例:港版 iPhone 的充電器是三孔插頭,可是現(xiàn)在房間只有二孔插頭,所以我得網(wǎng)上買個(gè)三孔轉(zhuǎn)二孔的轉(zhuǎn)換器(相當(dāng)于適配器),這樣我的三孔充電器就能在二孔插座使用了。
我們常用 ListView 使用的 Adapter ,用的就是適配器模式,Google 開發(fā)工程師,設(shè)計(jì)代碼的時(shí)候,考慮到 ListView 每個(gè) ItemView 有不同 UI。為了應(yīng)對(duì)這種可變性,BaseAdapter 提供 getView() 方法,以保證最后輸出的統(tǒng)一為 View。
public class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
六、觀察者模式
觀察者模式,多以一對(duì)多的形式依賴存在。多個(gè)觀察者同時(shí)監(jiān)聽著被監(jiān)聽的對(duì)象時(shí),當(dāng)被監(jiān)聽的對(duì)象發(fā)生狀態(tài)變化時(shí)候,會(huì)通知所有觀察者更新。
如:郵件的訂閱功能,訂閱某個(gè)模塊,當(dāng)這個(gè)模塊有新的內(nèi)容更新,會(huì)給所有訂閱者發(fā)送郵件。
Android 中,觀察者模式使用的是比較頻繁的,例如:EventBus、RxJava等。最熟悉的就是 Adapter 的 notifyDataSetChanged() 方法了,大家可以點(diǎn)進(jìn)去看源碼,當(dāng)數(shù)據(jù)發(fā)生改變的時(shí)候,通知 itemView 重新布局。
/**
* 觀察者集合
*/
private final DataSetObservable mDataSetObservable = new DataSetObservable();
//此處,省略很多代碼...
/**
* Notifies the attached observers that the underlying data has been changed
* and any View reflecting the data set should refresh itself.
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}