1. 程式人生 > >安卓常見設計模式整理

安卓常見設計模式整理

  • 監聽器模式
  1. 監聽器模式定義:

事件源經過事件的封裝傳給監聽器,當事件源觸發事件後,監聽器接收到事件物件可以回撥事件的方法

  1. 監聽器角色:
  • 事件源:具體的事件源,註冊特定的監聽,才可以對事件進行響應。
  • 事件物件:封裝了事件源物件以及與事件相關的資訊,是在事件源和事件監聽器之間傳遞資訊的角色。
  • 事件監聽器:監聽事件,並進行事件處理或者轉發,必須註冊在事件源上。
  1. 使用匿名內部類的方式實現監聽事件
  • 首先為要實現監聽的物件繫結監聽器,例如為一個Button物件繫結一個監聽器botton.setOnClickListener();
  • 然後在setOnClickListener()方法中定義一個OnClickListener的匿名內部類,然後重寫內部類中的onClick方法。
  • 最後在onClick方法中實現監聽事件要實現的邏輯即可。
  1. UML

http://dl2.iteye.com/upload/attachment/0115/5513/8129c489-e633-332b-934b-f1d02da88cd1.png

  1. 執行順序:
  • 給事件源註冊監聽器
  • 元件接受外部作用,也就是事件被觸發
  • 元件產生一個相應的事件物件,並把此物件傳遞給與之關聯的事件處理器
  • 事件處理器啟動,並執行相關的程式碼來處理該事件。

 

 

  • 工廠模式
  1. 工廠模式定義:

一個用於建立物件的介面,讓子類決定例項化哪個類

 

  1. 分類:

普通工廠模式:生產具體的產品,建立的產品是類(Class)
抽象工廠模式:生產抽象的產品,建立的產品是介面(Interface)

 

  1. 特徵:

多用於需要生成複雜物件的地方。用new就可以完成建立的物件就無需使用。工廠模式降低了物件之間的耦合度,由於工廠模式依賴抽象的架構,例項化的任務交由子類去完成,所以有很好的擴充套件性。

 

  1. 工廠模式主要分為四大模組:
  • 抽象工廠,其為工廠方法模式的核心。
  • 具體工廠,其實現了具體的業務邏輯。
  • 抽象產品,是工廠方法模式所建立的產品的父類。
  • 具體產品,為實現抽象產品的某一個具體產品物件。

 

  1. 工廠方法UML

  1. 原始碼分析
  • public Object getSystemService(String name) {
    if (getBaseContext() == null) {
    throw new IllegalStateException("System services not available to Activities before onCreate()");
    }
    //........
    if (WINDOW_SERVICE.equals(name)) {
    return mWindowManager;
    } else if (SEARCH_SERVICE.equals(name)) {
    ensureSearchManager();
    return mSearchManager;
    }
    //.......
    return super.getSystemService(name);
    }
  • getSystemService方法中就是用到了簡單工廠模式,根據傳入的引數決定建立哪個物件,由於這些物件以單例模式提前建立好了,所以此處不用new了,直接把單例返回就好。

 

  • 單例模式
  1. 單例模式定義:

因程式需要,有時我們只需要某個類同時保留一個物件,不希望有更多物件,此時,我們則應考慮單例模式的設計。

  1. 單例模式的特點:
  • 單例模式只能有一個例項。
  • 單例類必須建立自己的唯一例項。
  • 單例類必須向其他物件提供這一例項。
  1. 單例模式區別靜態類
  • 單例可以繼承和被繼承,方法可以被override,而靜態方法不可以。
  • 靜態方法中產生的物件會在執行後被釋放,進而被GC清理,不會一直存在於記憶體中。
  • 靜態類會在第一次執行時初始化,單例模式可以有其他的選擇,即可以延遲載入。
  • 基於2 3條,由於單例物件往往存在於DAO層(例如sessionFactory),如果反覆的初始化和釋放,則會佔用很多資源,而使用單例模式將其常駐於記憶體可以更加節約資源。
  • 靜態方法有更高的訪問效率。
  • 單例模式很容易被測試。
  1. UML類圖

角色介紹:

  • 1Client--高層客戶端;
  • 2Singleton--單例類。

實現單例模式主要有如下幾個關鍵點:

  • 1)建構函式不對外開放,一般為Private
  • 2)通過一個靜態方法或者列舉返回單例類物件;
  • 3)確保單例類的物件有且只有一個,尤其是在多執行緒環境下;
  • 4)確保單例類物件在反序列化時不會重新構建物件。
  1. 原始碼分析:
  • //獲取WindowManager服務引用
  • WindowManager   wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);
     
  • 其內部就是通過單例的方式持有一個WindowManager並返回這個物件

 

  1. 總結:

通過將單例類的建構函式私有化,使得客戶端程式碼不能通過new的形式手動構造單例類的物件。單例類會暴露一個公有靜態方法,客戶端需要呼叫這個靜態方法獲取到單例類的唯一物件,在獲取這個單例物件的過程中需要確保執行緒安全,即在多執行緒環境下構造單例類的物件也是有且只有一個,這也是單例模式實現中比較困難的地方。

 

 

  • 觀察者模式
  1. 觀察者模式定義

一個被觀察者管理所有相依於它的觀察者物件,並且在本身的狀態改變時主動發出通知。這通常通過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。

  1. 角色
  • 抽象被觀察者角色:把所有對觀察者物件的引用儲存在一個集合中,每個被觀察者角色都可以有任意數量的觀察者。被觀察者提供一個介面,可以增加和刪除觀察者角色。一般用一個抽象類和介面來實現。
  • 抽象觀察者角色:為所有具體的觀察者定義一個介面,在得到主題的通知時更新自己。
  • 具體被觀察者角色:在被觀察者內部狀態改變時,給所有登記過的觀察者發出通知。具體被觀察者角色通常用一個子類實現。
  • 具體觀察者角色:該角色實現抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀態相協調。通常用一個子類實現。如果需要,具體觀察者角色可以儲存一個指向具體主題角色的引用。
  1. 適用場景
  • 1) 當一個抽象模型有兩個方面, 其中一個方面依賴於另一方面。將這二者封裝在獨立的物件中以使它們可以各自獨立地改變和複用。
  • 2) 當對一個物件的改變需要同時改變其它物件, 而不知道具體有多少物件有待改變。
  • 3) 當一個物件必須通知其它物件,而它又不能假定其它物件是誰。換言之, 你不希望這些物件是緊密耦合的。
  1. 觀察者模式UML

  1. 原始碼分析

ListView的介面卡有個notifyDataSetChange()函式,就是通知ListView的每個Item,資料來源發生了變化,各個子Item需要重新重新整理一下。

  1. 觀察者模式總結

Android中,有很多場景使用了觀察者模式,比如Android的原始碼裡:OnClickListenerContentObserverandroid.database.Observable等;還有第三方開源庫EventBusRxJavaRxAndroid等。

 

  • 策略模式
  1. 策略模式定義

有一系列的演算法,將每個演算法封裝起來(每個演算法可以封裝到不同的類中),各個演算法之間可以替換,策略模式讓演算法獨立於使用它的客戶而獨立變化。

  1. 使用場景
  • 針對同一型別的問題有多重解決方式,僅僅是具體行為有差異時。讓系統可以動態的選擇演算法策略。
  • 需要安全的封裝多重同一類物件時,呼叫者不會知道演算法策略的具體過程。
  • 一個類有多個子類,並且在呼叫的時候用ifswitch判斷的時候。
  1. 優點
  • 結構清晰明瞭,消除了程式碼中的一大串選擇語句,而是分離為一個個獨立的類,程式碼更清晰。
  • 耦合度低,都是基於介面呼叫和實現,便於拓展和修改。
  • 封裝更徹底,資料更安全。
  1. 缺點
  • 首先是會產生很多策略類,增加了系統開銷。
  • 使用者要知道所有的策略類。

 

  1. UML

  1. 原始碼分析
  • Android在屬性動畫中使用時間插值器的時候就用到了策略模式。在使用動畫時,可以選擇線性插值器LinearInterpolator、加速減速插值器AccelerateDecelerateInterpolator、減速插值器DecelerateInterpolator以及自定義的插值器。這些插值器都是實現根據時間流逝的百分比來計算出當前屬性值改變的百分比。通過根據需要選擇不同的插值器,實現不同的動畫效果。
  1. 總結
  • 策略模式主要就是為了分離演算法和使用,是系統用於很好的拓展性。

 

  • 介面卡模式
  1. 介面卡模式定義:

將一個類的介面轉換成客戶希望的另一個介面。介面卡模式讓那些介面不相容的類可以一起工作;介面卡模式的別名為包裝器(Wrapper)模式,它既可以作為類結構型模式,也可以作為物件結構型模式。在介面卡模式定義中所提及的介面是指廣義的介面,它可以表示一個方法或者方法的集合。

  1. 介面卡模式包含三個角色:
  • Target(目標抽象類):目標抽象類定義客戶所需的介面,可以是一個抽象類或介面,也可以是具體類。
  • Adapter(介面卡類):它可以呼叫另一個介面,作為一個轉換器,對AdapterTarget進行適配。它是介面卡模式的核心。
  • Adapter(適配者類):適配者即被適配的角色,它定義了一個已經存在的介面,這個介面需要適配,適配者類包好了客戶希望的業務方法。
  1. 介面卡模式的優缺點
  • 優點:
  • 將目標類和適配者類解耦,通過引入一個介面卡類來重用現有的適配者類,無需修改原有結構。
  • 增加了類的透明性和複用性,將具體的業務實現過程封裝在適配者類中,對於客戶端類而言是透明的,而且提高了適配者的複用性,同一適配者類可以在多個不同的系統中複用。
  • 靈活性和擴充套件性都非常好,通過使用配置檔案,可以很方便的更換介面卡,也可以在不修改原有程式碼的基礎上 增加新的介面卡,完全複合開閉原則。
  • 缺點:
  • 一次最多隻能適配一個適配者類,不能同時適配多個適配者。
  • 適配者類不能為最終類。
  • 目標抽象類只能為介面,不能為類,其使用有一定的侷限性。
  1. 介面卡模式的適用環境
  • 系統需要使用一些現有的類,而這些類的介面不符合系統的需要,甚至沒有這些類的原始碼。
  • 建立一個可以重複使用的類,用於和一些彼此之間沒有太大關聯的類,包括一些可能在將來引進的類一起工作。
  • 當想使用一個既有類的介面,但是這個既有類與目前的程式碼結構不相相容的時候可以考慮使用介面卡模式。
  1. 類介面卡模式UML

  1. 物件介面卡模式UML

  1. 原始碼分析
  • 比較典型的有ListViewRecyclerView
  • ListView用於顯示列表資料,但列表資料形式多種多樣,為了處理和顯示不同的資料,我們需要對應的介面卡作為橋樑。這樣ListView就可以只關心它的每個ItemView,而不用關心這個ItemView具體顯示的是什麼。而我們的資料來源存放的是要顯示的內容,它儲存了每一個ItemView要顯示的內容。ListView和資料來源之間沒有任何關係,這時候,需要通過介面卡,介面卡提供getView方法給ListView使用,每次ListView只需提供位置資訊給getView函式,然後getView函式根據位置資訊向資料來源獲取對應的資料,根據資料返回不同的View
  • RecyclerView封裝了viewholder的回收複用,也就是說RecyclerView標準化了ViewHolder編寫Adapter面向的是ViewHolder而不再是View了,複用的邏輯被封裝了,寫起來更加簡單。
  • 提供了一種插拔式的體驗,高度的解耦,異常的靈活,針對一個Item的顯示RecyclerView專門抽取出了相應的類,來控制Item的顯示,使其的擴充套件性非常強。

 

 

  • 代理模式
  1. 代理模式定義

為其他物件提供一種代理以控制這個物件的訪問。代理模式屬於結構型模式。代理模式也叫委託模式。在生活中,比如代購、打官司等等,實際上都是一種代理模式。

  1. 角色
  • Subject(抽象主題類):介面或者抽象類,宣告真實主題與代理的共同介面方法。
  • RealSubject(真實主題類):也叫做被代理類或被委託類,定義了代理所表示的真實物件,負責具體業務邏輯的執行,客戶端可以通過代理類間接的呼叫真實主題類的方法。
  • Proxy(代理類):也叫委託類,持有對真實主題類的引用,在其所實現的介面方法中呼叫真實主題類中相應的介面方法執行。
  • Client(客戶端類):使用代理模式的地方。

 

  1. 分類
  • 靜態代理
  • 靜態代理就是在程式執行前就已經存在代理類的位元組碼檔案,代理類和委託類的關係在執行前就確定了。上面的例子實現就是靜態代理。
  • 動態代理
  • 動態代理類的原始碼是在程式執行期間根據反射等機制動態的生成,所以不存在代理類的位元組碼檔案。代理類和委託類的關係是在程式執行時確定。
  1. UML

 

 
 

 

 

 

  1. 原始碼分析
  • AIDL會根據當前的執行緒判斷是否要跨程序訪問,如果不需要跨程序就直接返回例項,如果需要跨程序則返回一個代理。
  • 在跨程序通訊時,需要把引數寫入到Parcelable物件,然後再執行transact函式,AIDL通過生成一個代理類,這個代理類會自動幫我們寫好這些操作。而要實現Android的外掛化開發,動態代理更是必不可少的。

 

 

  • 迭代器模式
  1. 迭代器模式定義

提供一種方法訪問一個容器物件中各個元素,而又不需暴露該物件的內部細節。迭代器模式屬於行為型模式。迭代器(Iterator)模式,又叫做遊標(Cursor)模式。Java中的MapList等等容器,都使用到了迭代器模式。

  1. 迭代器模式角色:
  • Iterator:迭代器介面,迭代器介面負責定義、訪問和遍歷元素的介面。
  • ConcreteIterator:具體迭代器類,具體迭代器類的目的主要是實現迭代器介面,並記錄遍歷的當前位置。
  • Aggregate:容器介面,容器介面負責提供建立具體迭代器角色的介面。
  • ConcreteAggregate:具體容器類,具體迭代器角色與該容器相關聯。
  • Client:客戶類
  1. 應用場景
  • 遍歷一個容器物件時。
  • 實際我們開發中很少使用到迭代器模式。雖然不怎麼用得到,但是瞭解其原理能夠讓我們在看到相關的原始碼(如Java中的MapList等等容器)時能夠更容易瞭解原始碼的相關思想。
  1. 優點
  • 迭代子模式簡化了聚集的介面,迭代子具備了一個遍歷介面,這樣聚集的介面就不必具備遍歷介面;
  • 每一個聚集物件都可以有一個或多個迭代子物件,每一個迭代子的迭代狀態可以是彼此獨立的。因此,一個聚集物件可以同時有幾個迭代在進行之中;
  • 由於遍歷演算法被封裝在迭代子角色裡面,因此迭代的演算法可以獨立於聚集角色變化。
  1. 缺點
  • 會產生多餘的物件,消耗記憶體。
  • 會增多類檔案。
  • 遍歷過程是一個單向且不可逆的遍歷。
  • 遍歷過程需要注意容器是否改變,若期間改變了,可能會丟擲異常。
  1. UML

  1. 原始碼分析
  • Android原始碼中,最典型的就是Cursor用到了迭代器模式,當我們使用SQLiteDatabasequery方法時,返回的就是Cursor物件,之後再通過Cursor去遍歷資料
  1. 總結
  • 迭代器模式提供一種方法來訪問聚合物件,而不用暴露這個物件的內部表示。
  • 將遍歷聚合物件中資料的行為提取出來,封裝到一個迭代器中,通過專門的迭代器來遍歷聚合物件的內部資料,這就是迭代器模式的本質。迭代器模式是“單一職責原則”的完美體現。
  • 當使用迭代器的時候,我們依賴聚合提供遍歷。
  • 迭代器提供了一個通用的介面,讓我們遍歷聚合的項,放我們編碼使用聚合項時,就可以使用多型機制。

 

參考文獻:

  1. https://www.jianshu.com/p/b2d62447c9ea
  2. https://www.cnblogs.com/jackson-zhangjiang/p/7784694.html
  3. https://www.cnblogs.com/jackson-zhangjiang/p/7784694.html
  4. https://www.cnblogs.com/jackson-zhangjiang/p/7784694.html
  5. http://book.51cto.com/art/201511/498711.htm
  6. https://www.cnblogs.com/cielosun/p/6582333.html
  7. https://blog.csdn.net/jason0539/article/details/45055233
  8. https://www.jianshu.com/p/bb9b46ac41e4
  9. https://www.cnblogs.com/songyaqi/p/4805820.html
  10. https://www.jianshu.com/p/a0e687e0904f
  11. https://blog.csdn.net/self_study/article/details/52502709
  12. https://www.jianshu.com/p/f4917cb02752