前言
當自己的編碼時間久了之後,會發現優秀的程式碼,往往是遵循合理的設計模式進行開發的,這些程式碼具備高內聚、低耦合的特性,能夠在隨時變化的需求中,保持穩定性、靈活性。
本文,是在 Android 程式碼中去尋找「設計模式」的影子,並不會很詳細地展開各個模式的定義與應用。文中選取的例子都是儘量簡單易懂的,主要讓大家知道平時原來自己也是用著各種設計模式,只是不知道名字而已,開始盤它!
(篇幅有限且網上優秀的書籍多,所以不要想著在這一篇文章弄清楚它們。注:本人水平有限,不對的地方,還請指出修正)。
一、單例模式
記得曾經筆試時就考過寫出單例模式的實現方式:1、懶漢式(執行緒安全);2、餓漢式(DCL);3、靜態內部類;4、列舉實現(最佳實現)。
當某個物件的建立是比較耗時的,如果頻繁的建立與銷燬的話,對效能影響又大,既然沒有好的辦法優化,那就在記憶體中持有這個物件的唯一例項,減少記憶體佔用。
值得注意的是:1、單例物件建立的執行緒安全問題;2、Android 中建立單例時,如果持有 Context 容易導致記憶體洩露,儘量使用 Application Context。
例如 Glide
、ImageLoader
圖片載入框架,正是採用單例模式,來獲取例項物件的。
1、Glide.with(context).load(imageUrl).into(imageView);
2、ImageLoader.getInstance().displayImage(imageUrl,imageView);
複製程式碼
二、Builder 模式
構建者模式把一個物件的建立與表示分離開了,也就是說構建的過程不同,會生產出不同的物件出來。同時 Builder 類,把具體產品的建立細節隱藏了,使得我們不用關注產品具體是怎麼實現的。例如:我們無需關注呼叫方法的順序,因為 Builder 類已經封裝好了呼叫的順序了。還有這種鏈式呼叫寫起來真的很爽!
最常見的就是我們 Android 裡面的對話方塊的建立過程了,我們通過 AlertDialog.Builder()
構建的過程中,有沒有設定按鈕、標題、提示等,其實建立出來的對話方塊風格是不一樣的。
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();
複製程式碼
這裡介紹一個 Android Studio
的外掛 —— Builder Generator
,這個外掛可以省去手寫 Builder
的煩惱。
三、工廠模式
有以下幾種:
- 簡單工廠:含靜態方法,也叫靜態工廠,多用 if...else 來做分支,去建立各個例項,方法內部如果建立的物件多的,會略顯臃腫
- 工廠模式:含抽象工廠、具體工廠、抽象產品、具體產品之分,符合“開閉原則”
- 抽象工廠模式:與工廠模式的區別,工廠模式建立單一產品,抽象工廠能建立多種產品,符合“開閉原則”
工廠類封裝好類的例項化過程,隱藏了物件例項化的具體引數,只需傳入要建立類的唯一標識,工廠類就能建立出指定的類。換句話說:我只告訴工廠我要什麼,工廠只負責生產,我負責使用,具體工廠怎麼生產,我就不管啦~
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;
}
}
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/bitmap.png");
複製程式碼
如 Retrofit
可新增 Gson
轉換(這裡體現了 Builder 模式 和工廠模式)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
複製程式碼
四、策略模式
將演算法單獨封裝起來,使之替換時,互不影響。
之前看過一篇文章說怎麼消除專案程式碼中的 if...else ,運用策略模式,將每個 if...else 裡面的方法各自封裝,來解決因為大量的 if...else 導致的類臃腫。
例如:android 中的設定動畫的插值器,替換不同插值器,各不影響,而且效果不同
Animation animation = new AlphaAnimation(1,0);
animation.setInterpolator(new AccelerateDecelerateInterpolator());
imageView.setAnimation(animation);
animation.start();
複製程式碼
五、模版模式
在抽象類中,定義模版(抽象)方法,並在子類做具體的實現。其實就是我們經常用的 BaseActivity
、BaseFragment
那套東西,show code~
在 BaseActivity
裡面保證模版方法,按照順序執行,同時子類必須實現父類定義的抽象方法,提高了複用性以及擴充套件性。
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 1、獲取佈局id
setContentView(getLayoutId());
// 2、初始化 view
initView();
// 3、初始化資料
initData();
}
public abstract int getLayoutId();
public abstract void initView();
public abstract void initData();
}
複製程式碼
六、介面卡模式
介面卡模式,可以解決介面不相容的問題,使得本不相容的介面一起工作。
舉例:港版 iPhone 的充電器是三孔插頭,可是現在房間只有二孔插頭,所以我得網上買個三孔轉二孔的轉換器(相當於介面卡),這樣我的三孔充電器就能在二孔插座使用了。
我們常用 ListView
使用的 Adapter
,用的就是介面卡模式,Google 開發工程師,設計程式碼的時候,考慮到 ListView
每個 ItemView
有不同 UI
。為了應對這種可變性,BaseAdapter 提供 getView() 方法,以保證最後輸出的統一為 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;
}
}
複製程式碼
七、觀察者模式
觀察者模式,多以一對多的形式依賴存在。多個觀察者同時監聽著被監聽的物件時,當被監聽的物件發生狀態變化時候,會通知所有觀察者更新。
如:郵件的訂閱功能,訂閱某個模組,當這個模組有新的內容更新,會給所有訂閱者傳送郵件。
Android 中,觀察者模式使用的是比較頻繁的,例如:EventBus
、RxJava
等。最熟悉的就是 Adapter
的 notifyDataSetChanged()
方法了,大家可以點進去看原始碼,當資料發生改變的時候,通知 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();
}
複製程式碼
推薦閱讀
更多技術分享,請關注微信公眾號——碼農茅草屋: