當本身的編碼時間久了以後,會發現優秀的代碼,每每是遵循合理的設計模式進行開發的,這些代碼具有高內聚、低耦合的特性,可以在隨時變化的需求中,保持穩定性、靈活性。html
本文,是在 Android 代碼中去尋找「設計模式」的影子,並不會很詳細地展開各個模式的定義與應用。文中選取的例子都是儘可能簡單易懂的,主要讓你們知道平時原來本身也是用着各類設計模式,只是不知道名字而已,開始盤它!java
(篇幅有限且網上優秀的書籍多,因此不要想着在這一篇文章弄清楚它們。注:本人水平有限,不對的地方,還請指出修正)。android
記得曾經筆試時就考過寫出單例模式的實現方式:一、懶漢式(線程安全);二、餓漢式(DCL);三、靜態內部類;四、枚舉實現(最佳實現)。git
當某個對象的建立是比較耗時的,若是頻繁的建立與銷燬的話,對性能影響又大,既然沒有好的辦法優化,那就在內存中持有這個對象的惟一實例,減小內存佔用。github
值得注意的是:一、單例對象建立的線程安全問題;二、Android 中建立單例時,若是持有 Context 容易致使內存泄露,儘可能使用 Application Context。算法
例如 Glide
、ImageLoader
圖片加載框架,正是採用單例模式,來獲取實例對象的。設計模式
一、Glide.with(context).load(imageUrl).into(imageView);
二、ImageLoader.getInstance().displayImage(imageUrl,imageView);
複製代碼
構建者模式把一個對象的建立與表示分離開了,也就是說構建的過程不一樣,會生產出不一樣的對象出來。同時 Builder 類,把具體產品的建立細節隱藏了,使得咱們不用關注產品具體是怎麼實現的。例如:咱們無需關注調用方法的順序,由於 Builder 類已經封裝好了調用的順序了。還有這種鏈式調用寫起來真的很爽!安全
最多見的就是咱們 Android 裏面的對話框的建立過程了,咱們經過 AlertDialog.Builder()
構建的過程當中,有沒有設置按鈕、標題、提示等,其實建立出來的對話框風格是不同的。markdown
一、new AlertDialog.Builder()
.setTitle("title")
.setMessage("message")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// do something
}
}).create();
二、new StringBuilder().append("A").append("B").append("C").toString();
複製代碼
這裏介紹一個 Android Studio
的插件 —— Builder Generator
,這個插件能夠省去手寫 Builder
的煩惱。app
有如下幾種:
- 簡單工廠:含靜態方法,也叫靜態工廠,多用 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);
// 一、獲取佈局id
setContentView(getLayoutId());
// 二、初始化 view
initView();
// 三、初始化數據
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();
}
複製代碼