Android 設計模式

來源:互聯網
上載者:User

簡介

項目開發中發現問題、解決問題這個過程中會出現很多問題,比如重複出現、某個問題的遺留,這些問題的本質就是設計模式。今天記錄設計模式的知識點。

內容

在java以及其他的物件導向設計模式中,類與類之間主要有6種關係,他們分別是:依賴、關聯、彙總、組合、繼承、實現。它們的耦合度依次增強。

依賴關係:
對於兩個相對獨立的對象,當一個對象負責構造另一個對象的執行個體,或者依賴另一個對象的服務時,這兩個對象之間主要體現為依賴關係。
關聯關係:
分為單向關聯和雙向關聯。在java中,單向關聯表現為:類A當中使用了類B,其中類B是作為類A的成員變數。雙向關聯表現為:類A當中使用了類B作為成員變數;同時類B中也使用了類A作為成員變數。
彙總關係:
是關聯關係的一種,耦合度強於關聯,他們的代碼錶現是相同的,僅僅是在語義上有所區別:關聯關係的對象間是相互獨立的,而彙總關係的對象之間存在著包容關係,他們之間是“整體-個體”的相互關係。
組合關係:
是一種耦合度更強的關聯關係。存在組合關係的類表示“整體-部分”的關聯關係,“整體”負責“部分”的生命週期,他們之間是共生共死的;並且“部分”單獨存在時沒有任何意義。
繼承:
表示類與類(或者介面與介面)之間的父子關係。
實現:
表示一個類實現一個或多個介面的方法。


設計原則

要點 定義 描述
單一職責原則 不要存在多於一個導致類變更的原因。通俗的說,即一個類只負責一項職責。 問題由來:類T負責兩個不同的職責:職責P1,職責P2。當由於職責P1需求發生改變而需要修改類T時,有可能會導致原本運行正常的職責P2功能發生故障。

解決方案:遵循單一職責原則。分別建立兩個類T1、T2,使T1完成職責P1功能,T2完成職責P2功能。這樣,當修改類T1時,不會使職責P2發生故障風險;同理,當修改T2時,也不會使職責P1發生故障風險。
裡氏替換原則 定義1:如果對每一個類型為 T1的對象 o1,都有類型為 T2 的對象o2,使得以 T1定義的所有程式 P 在所有的對象 o1 都代換成 o2 時,程式 P 的行為沒有發生變化,那麼類型 T2 是類型 T1 的子類型。
定義2:所有引用基類的地方必須能透明地使用其子類的對象。
問題由來:有一功能P1,由類A完成。現需要將功能P1進行擴充,擴充後的功能為P,其中P由原有功能P1與新功能P2組成。新功能P由類A的子類B來完成,則子類B在完成新功能P2的同時,有可能會導致原有功能P1發生故障。

解決方案:當使用繼承時,遵循裡氏替換原則。類B繼承類A時,除添加新的方法完成新增功能P2外,盡量不要重寫父類A的方法,也盡量不要重載父類A的方法。
依賴倒置原則 高層模組不應該依賴低層模組,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。 問題由來:類A直接依賴類B,假如要將類A改為依賴類C,則必須通過修改類A的代碼來達成。這種情境下,類A一般是高層模組,負責複雜的商務邏輯;類B和類C是低層模組,負責基本的原子操作;假如修改類A,會給程式帶來不必要的風險。

解決方案:將類A修改為依賴介面I,類B和類C各自實現介面I,類A通過介面I間接與類B或者類C發生聯絡,則會大大降低修改類A的幾率。
介面隔離原則 用戶端不應該依賴它不需要的介面;一個類對另一個類的依賴應該建立在最小的介面上。 問題由來:類A通過介面I依賴類B,類C通過介面I依賴類D,如果介面I對於類A和類B來說不是最小介面,則類B和類D必須去實現他們不需要的方法。

解決方案:將臃腫的介面I拆分為獨立的幾個介面,類A和類C分別與他們需要的介面建立依賴關係。也就是採用介面隔離原則。
迪米特法則 一個對象應該對其他對象保持最少的瞭解。 問題由來:類與類之間的關係越密切,耦合度越大,當一個類發生改變時,對另一個類的影響也越大。

解決方案:盡量降低類與類之間的耦合。
開閉原則 一個軟體實體如類、模組和函數應該對擴充開放,對修改關閉。 問題由來:在軟體的生命週期內,因為變化、升級和維護等原因需要對軟體原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行重構,並且需要原有代碼經過重新測試。

解決方案:當軟體需要變化時,盡量通過擴充軟體實體的行為來實現變化,而不是通過修改已有的代碼來實現變化。
     

設計模式

要點 定義 描述
單例模式 確保一個類只有一個執行個體,而且自行執行個體化並向整個系統提供這個執行個體。 單例模式注意事項:
只能使用單例類提供的方法得到單例對象,不要使用反射,否則將會執行個體化一個新對象。不要做斷開單例類對象與類中靜態引用的危險操作。多線程使用單例使用共用資源時,注意安全執行緒問題。
Factory 方法模式 定義一個用於建立對象的介面,讓子類決定執行個體化哪一個類,Factory 方法使一個類的執行個體化延遲到其子類。 在Factory 方法模式中,核心的工廠類不再負責所有的對象的建立,而是將具體建立的工作交給子類去做。這個核心類則搖身一變,成為了一個抽象工廠角色,僅負責給出具體工廠子類必須實現的介面,而不接觸哪一個類應當被執行個體化這種細節。
抽象原廠模式 為建立一組相關或相互依賴的對象提供一個介面,而且無需指定他們的具體類。 在以下情況下,適用於Factory 方法模式:
(1) 當一個類不知道它所必須建立的對象的類的時候。
(2) 當一個類希望由它的子類來指定它所建立的對象的時候。
(3) 當類將建立對象的職責委託給多個協助子類中的某一個,並且你希望將哪一個協助子類是代理者這一資訊局部化的時候。
模版方法模式 定義一個操作中演算法的架構,而將一些步驟延遲到子類中,使得子類可以不改變演算法的結構即可重定義該演算法中的某些特定步驟。 子類可以置換掉父類的可變部分,但是子類卻不可以改變模板方法所代表的頂級邏輯。
  每當定義一個新的子類時,不要按照控制流程程的思路去想,而應當按照“責任”的思路去想。換言之,應當考慮哪些操作是必須置換掉的,哪些操作是可以置換掉的,以及哪些操作是不可以置換掉的。使用模板模式可以使這些責任變得清晰。
建造者模式 將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。 與抽象工廠的區別:在建造者模式裡,有個指導者,由指導者來管理建造者,使用者是與指導者聯絡的,指導者聯絡建造者最後得到產品。即建造模式可以強制實行一種分步驟進行的建造過程。
  建造模式是將複雜的內部建立封裝在內部,對於外部調用的人來說,只需要傳入建造者和建造工具,對於內部是如何建造成成品的,調用者無需關心。
在Java的應用中JavaMail使用到了該模式。
代理模式 為其他對象提供一種代理以控制對這個對象的訪問。 所謂代理,就是一個人或者機構代表另一個人或者機構採取行動。在一些情況下,一個客戶不想或者不能夠直接引用一個對象,而代理對象可以在用戶端和目標對象之間起到中介的作用。
原型模式 用原型執行個體指定建立對象的種類,並通過拷貝這些原型建立新的對象。

原型模式要求對象實現一個可以“複製”自身的介面,這樣就可以通過複製一個執行個體對象本身來建立一個新的執行個體。這樣一來,通過原型執行個體建立新的對象,就不再需要關心這個執行個體本身的類型,只要實現了複製自身的方法,就可以通過這個方法來擷取新的對象,而無須再去通過new來建立。
在Java語言裡深度複製一個對象,常常可以先使對象實現Serializable介面,然後把對象(實際上只是對象的拷貝)寫到一個流裡(序列化),再從流裡讀回來(還原序列化),便可以重建對象。

原型模式的優點
  原型模式允許在運行時動態改變具體的實作類別型。原型模式可以在運行期間,由客戶來註冊符合原型介面的實作類別型,也可以動態地改變具體的實作類別型,看起來介面沒有任何變化,但其實啟動並執行已經是另外一個類執行個體了。因為複製一個原型就類似於執行個體化一個類。

原型模式的缺點
  原型模式最主要的缺點是每一個類都必須配備一個複製方法。配備複製方法需要對類的功能進行通盤考慮,這對於全新的類來說不是很難,而對於已經有的類不一定很容易,特別是當一個類引用不支援序列化的間接對象,或者引用含有迴圈結構的時候。
中介者模式 用一個中介者對象封裝一系列的對象互動,中介者使各對象不需要顯示地相互作用,從而使耦合鬆散,而且可以獨立地改變它們之間的互動。

中介者模式的優點
適當地使用中介者模式可以避免同事類之間的過度耦合,使得各同事類之間可以相對獨立地使用。
使用中介者模式可以將對象間一對多的關聯轉變為一對一的關聯,使對象間的關係易於理解和維護。
使用中介者模式可以將對象的行為和協作進行抽象,能夠比較靈活的處理對象間的相互作用。
適用情境
       在物件導向編程中,一個類必然會與其他的類發生依賴關係,完全獨立的類是沒有意義的。一個類同時依賴多個類的情況也相當普遍,既然存在這樣的情況,說明,一對多的依賴關係有它的合理性,適當的使用中介者模式可以使原本淩亂的對象關係清晰,但是如果濫用,則可能會帶來反的效果。一般來說,只有對於那種同事類之間是網狀結構的關係,才會考慮使用中介者模式。可以將網狀結構變為星狀結構,使同事類之間的關係變的清晰一些。
       中介者模式是一種比較常用的模式,也是一種比較容易被濫用的模式。對於大多數的情況,同事類之間的關係不會複雜到混亂不堪的網狀結構,因此,大多數情況下,將對象間的依賴關係封裝的同事類內部就可以的,沒有必要非引入中介者模式。濫用中介者模式,只會讓事情變的更複雜。
命令模式 意圖:將一個請求封裝為一個對象,從而可用不同的請求對客戶進行參數化;對請求排隊或記錄日誌,以及支援可撤銷的操作
動機:將”發出請求的對象”和”接收與執行這些請求的對象”分隔開來。
常見應用:
1、工作隊列,線程池,排程
2、日誌請求(系統復原)
要點:
1、命令模式將發出請求的對象和執行請求的對象解耦
2、在被解耦的兩者之間是通過命令對象進行溝通的。命令對象封裝了接收者和一個或一組動作
3、調用者通過調用命令對象的execute()發出請求,這會使得接收者的動作被調用
4、調用者可以接受命令當作參數,甚至在運行時動態進行
5、命令可以支援撤銷,做法是實現一個undo()方法來回到execute()被執行前的狀態
6、宏命令是命令的一種簡單的延伸,允許調用多個命令。宏方法也可以支援撤銷
7、實際操作時,很常見使用"聰明"命令對象,也就是直接實現了請求,而不是將工作委託給接受者(弊端?)
8、命令也可以用來實現日誌和事物系統
責任鏈模式 使多個對象都有機會處理請求,從而避免了請求的寄件者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有對象處理它為止。 一個純的責任鏈模式要求一個具體的處理者對象只能在兩個行為中選擇一個:一是承擔責任,而是把責任推給下家。不允許出現某一個具體處理者對象在承擔了一部分責任後又 把責任向下傳的情況。
  在一個純的責任鏈模式裡面,一個請求必須被某一個處理者對象所接收;在一個不純的責任鏈模式裡面,一個請求可以最終不被任何接收端對象所接收。
  純的責任鏈模式的實際例子很難找到,一般看到的例子均是不純的責任鏈模式的實現。有些人認為不純的責任鏈根本不是責任鏈模式,這也許是有道理的。但是在實際的系統裡,純的責任鏈很難找到。如果堅持責任鏈不純便不是責任鏈模式,那麼責任鏈模式便不會有太大意義了。
裝飾模式 又名封裝(Wrapper)模式,裝飾模式以對用戶端透明的方式擴充項物件的功能,是繼承關係的一個替代方案。 裝飾模式與類繼承的區別:
1)    裝飾模式是一種動態行為,對已經存在類進行隨意組合,而類的繼承是一種靜態行為,一個類定義成什麼樣的,該類的對象便具有什麼樣的功能,無法動態改變。
2)    裝飾模式擴充的是對象的功能,不需要增加類的數量,而類繼承擴充是類的功能,在繼承的關係中,如果我們想增加一個對象的功能,我們只能通過繼承關係,在子類中增加兩個方法。
3)    裝飾與繼承比較圖:
4)    裝飾模式是在不改變原類檔案和使用繼承的情況下,動態擴充一個對象的功能,它是通過建立一個封裝對象,也就是裝飾來包裹真是的對象。
5.    裝飾模式把對用戶端的調用委派給被裝飾的類,裝飾模式的關鍵在於這種擴充完全透明的。
策略模式 定義一組演算法,將每個演算法都封裝起來,並且使他們之間可以互換。
策略模式的好處在於你可以動態改變對象的行為。
    策略模式屬於對象行為型模式,主要針對一組演算法,將每一個演算法封裝到具有共同介面的獨立的類中,從而使得它們可以相互替換。策略模式使得演算法可以在不影響 到用戶端的情況下發生變化。通常,策略模式適用於當一個應用程式需要實現一種特定的服務或者功能,而且該程式有多種實現方式時使用。
適配器模式 基於現有類所提供的服務,向客戶提供介面,以滿足客戶的期望。

適配器模式的用意是要改變源的介面,以便於目標介面相容。預設適配的用意稍有不同,它是為了方便建立一個不平庸的適配器類而提供的一種平庸實現。
適配器模式的優點
  更好的複用性
  系統需要使用現有的類,而此類的介面不符合系統的需要。那麼通過適配器模式就可以讓這些功能得到更好的複用。
  更好的擴充性
  在實現適配器功能的時候,可以調用自己開發的功能,從而自然地擴充系統的功能。
適配器模式的缺點
  過多的使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是A介面,其實內部被適配成了B介面的實現,一個系統如果太多出現這種情況,無異於一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
迭代器模式 提供一種方法訪問一個容器物件中各個元素,而又不暴露該對象的內部細節。 在jdk中,與迭代器相關的介面有兩個:Iterator 與 Iterable 
Iterator:迭代器,Iterator及其子類通常是迭代器本身的結構與方法; 
Iterable:可迭代的,那些想用到迭代器功能的其它類,如AbstractList HashMap等,需要實現該介面。 
組合模式 將對象組合成樹形結構以表示‘部分-整體’的階層。組合模式使得使用者對單個對象和組合對象的使用具有一致性。

對象通過實現(繼承)統一的介面(抽象類別),調用者對單一對象和組合對象的操作具有一致性。
通過實現組合模式,調用者對組合對象的操作與對單一對象的操作具有一致性。調用者不用關心這是組合對象還是檔案,也不用關心組合對象內部的具體結構,就可以調用相關方法,實現功能。
觀察者模式 定義對象間一種一對多的依賴關係,使得當每一個對象改變狀態,則所有依賴於它的對象都會得到通知並自動更新。

觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態上發生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。
在JAVA語言的java.util庫裡面,提供了一個Observable類以及一個Observer介面,構成JAVA語言對觀察者模式的支援。
門面模式 外部與一個子系統的通訊必須通過一個統一的門面對象進行。 門面模式的優點:
  ●  鬆散耦合
  門面模式鬆散了用戶端與子系統的耦合關係,讓子系統內部的模組能更容易擴充和維護。
  ●  簡單易用
  門面模式讓子系統更加易用,用戶端不再需要瞭解子系統內部的實現,也不需要跟眾多子系統內部的模組進行互動,只需要跟門面類互動就可以了。
  ●  更好的劃分訪問層次
  通過合理使用Facade,可以協助我們更好地劃分訪問的層次。有些方法是對系統外的,有些方法是系統內部使用的。把需要暴露給外部的功能集中到門面中,這樣既方便用戶端使用,也很好地隱藏了內部的細節。
備忘錄模式 在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外儲存這個狀態。這樣就可以將該對象恢複到原先儲存的狀態。 備忘錄對象是一個用來儲存另外一個對象內部狀態的快照的對象。備忘錄模式的用意是在不破壞封裝的條件下,將一個對象的狀態捕捉(Capture)住,並外部化,儲存起來,從而可以在將來合適的時候把這個對象還原到儲存起來的狀態。備忘錄模式常常與命令模式和迭代子模式一同使用。
訪問者模式 封裝某些作用於某種資料結構中各元素的操作,它可以在不改變資料結構的前提下定義作用於這些元素的新的操作。
訪問者模式是對象的行為模式。訪問者模式的目的是封裝一些施加於某種資料結構元素之上的操作。一旦這些操作需要修改的話,接受這個操作的資料結構則可以保持不變。
訪問者模式的優點
  好的擴充性
  能夠在不修改對象結構中的元素的情況下,為對象結構中的元素添加新的功能。
  好的複用性
  可以通過訪問者來定義整個對象結構通用的功能,從而提高複用程度。
  分離無關行為
  可以通過訪問者來分離無關的行為,把相關的行為封裝在一起,構成一個訪問者,這樣每一個訪問者的功能都比較單一。

訪問者模式的缺點
  對象結構變化很困難
  不適用於對象結構中的類經常變化的情況,因為對象結構發生了改變,訪問者的介面和訪問者的實現都要發生相應的改變,代價太高。
  破壞封裝
  訪問者模式通常需要對象結構開放內部資料給訪問者和ObjectStructrue,這破壞了對象的封裝性。
狀態模式 當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。
狀態模式允許一個對象在其內部狀態改變的時候改變其行為。這個對象看上去就像是改變了它的類一樣。
 
解譯器模式 給定一種語言,定義他的文法的一種表示,並定義一個解譯器,該解譯器使用該表示來解釋語言中句子。  
享元模式 複用我們記憶體中已存在的對象,降低系統建立對象執行個體的效能消耗。

Flyweight在拳擊比賽中指最輕量級,即“蠅量級”或“雨量級”,這裡選擇使用“享元模式”的意譯,是因為這樣更能反映模式的用意。享元模式是對象的結構模式。享元模式以共用的方式高效地支援大量的細粒度對象。
享元模式採用一個共用來避免大量擁有相同內容對象的開銷。這種開銷最常見、最直觀的就是記憶體的損耗。享元對象能做到共用的關鍵是區分內蘊狀態(Internal State)和外蘊狀態(External State)。
橋樑模式 將抽象和實現解耦,使得兩者可以獨立地變化。
橋樑模式的用意是“將抽象化(Abstraction)與實現化(Implementation)脫耦,使得二者可以獨立地變化”。
橋樑模式在Java應用中的一個非常典型的例子就是JDBC磁碟機。JDBC為所有的關係型資料庫提供一個通用的介面。一個應用系統動態地選擇一個合適的磁碟機,然後通過磁碟機向資料庫引擎發出指令。這個過程就是將抽象角色的行為委派給實現角色的過程。
     

項目

寫了一個Android的項目體現23中設計模式,項目




測試代碼:

public void onClickSingleMode(View view) { // 單例SingleMode.getInstance();}public void onClickFactoryMethodModel(View view) {// Factory 方法IProduct iProduct = new FactoryMethodModel();iProduct.productMethod();iProduct = new Tree();iProduct.productMethod();}public void onClickAbstractFactoryModel(View view) {// 抽象工廠AbstractFactoryModel.test();}public void onClickTemplateMethodModel(View view) {// 模版方法模式TemplateMethodModel.test();}public void onClickBuilderMode(View view) {// 建造者模式BuilderMode.test();}public void onClickProxyMode(View view) {// 代理模式ProxyMode.test();}public void onClickCloneMode(View view) {// 原型模式CloneMode.test();}public void onClickIntermediaryModel(View view) {// 中介者模式IntermediaryModel.test1();IntermediaryModel.test2();}public void onClickCommandMode(View view) {// 命令模式CommandMode.test();}public void onChainOfResponsibilityModel(View view) {// 責任鏈模式ChainOfResponsibilityModel.test();}public void onClickDecorativeMode(View view) {// 裝飾模式DecorativeMode.test();}public void onClickStrategyMode(View view) {// 策略模式StrategyMode.test();}public void onClickIteratorModel(View view) {// 模式IteratorModel.test();}public void onClickCombinationMode(View view) {// 組合模式CombinationMode.test();}public void onClickObserverMode(View view) {// 觀察者模式ObserverMode.test();}public void onClickWindowMode(View view) {// 門面模式WindowMode.test();}public void onClickMemoMode(View view) {// 備忘錄模式MemoMode.test();}public void onClickVisitorMode(View view) {// 訪問者模式VisitorMode.test();}public void onClickStateModel(View view) {// 狀態模式StateModel.test();}public void onClickParserMode(View view) {// 解譯器模式ParserMode.test();}public void onClickFlyweightMode(View view) {// 享元模式FlyweightMode.test();}public void onClickBridgeMode(View view) {// 橋樑模式BridgeMode.test();}


總結

如果設計模式在編碼設計生涯中用得極少,主要原因是對設計模式的理解還不夠,認識不到問題的存在。
因為不能正確的分析問題、認識問題,當然也不可能很好的解決問題了。


項目下載

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.