1. 程式人生 > >設計模式學習——設計原則與設計模式

設計模式學習——設計原則與設計模式

設計原則和模式
一、設計原則
1、單一職責原則:就一個類而言,應該僅有一個引起它變化的原因。換句話說,一個類的功能要單一,只做與它有關的事。(android的四大元件)
2、開放封閉原則:一個軟體實體應該對外擴充套件開放,對修改封閉。對擴充套件開放意味著有新的需求或變化時,可以對現有程式碼進行擴充套件,以適應新的情況;對修改封閉,意味著類一旦設計完成,就可以獨立工作,而不要對類進行任何的修改。
(1)開放封閉原則是所有面向物件原則的核心。
(2)如何做到開放封閉原則?——封裝變化,依賴介面和抽象類,而不要依賴具體實現類。要針對介面和抽象類程式設計,不要針對具體實現程式設計。
3、里氏代換原則(LSP):指一個軟體實現如果使用的是基類,那麼也一定適用於其子類,而且它根本察覺不出使用的是基類物件還是子類物件;反過來的代換是不成立的,即使用一個類的子類物件,那麼它不能夠適用於基類物件。也就是說,子類必須能夠替代他們的基類。抽象
(1)里氏代換原則講的是基類和子類的關係,是實現開放封閉原則的具體規範。
(2)違背了里氏代換原則就一定不符合開放封閉原則。
4、迪米特法則:又稱最少知識原則(LKP),也就是說,一個物件應當對其他物件儘可能少地瞭解。(android的NDK開發)
(1)狹義的迪米特法則:如果兩個類不必彼此直接通訊,那麼這兩個類就不應當發生直接的相互作用。如果其中一個類需要呼叫另一個類的某一個方法的話,可以通過第三者轉發這個呼叫。
(2)廣義的迪米特法則:一個模組設計好壞的一個重要標誌就是該模組在多大程度上將自己內部資料與實現的有關細節隱藏起來。
(3)應用迪米特法則到系統的設計中,要注意一下幾點:
A、在類的劃分上,應當建立弱耦合的類,類與類之間的耦合越弱,就越利於實現可複用的目標;
B、在類的結構設計上,每個類都應該降低成員的訪問許可權;
C、在類的設計上,只要有可能,一個類應當寫成不變的類;
D、在對其他類的應用上,一個物件對其他類的物件的應用應該降到最低;
E、儘量限制區域性變數的有效範圍。
5、依賴倒置原則:依賴倒置指代了一種特定的解耦方式,使得高層次的模組不依賴於低層次的模組的實現細節。模組間的依賴關係通過抽象實現,實現類之間不發生直接的依賴關係,其依賴關係通過介面或抽象產生。即面向抽象程式設計。
依賴倒置原則的幾個關鍵點:
(1)高層模組不依賴低層模組,兩者都應該依賴其抽象;
(2)抽象不應該依賴細節
(3)細節應該依賴抽象
6、介面隔離原則:客戶端不應該依賴它不需要的介面。即類間的依賴關係應該建立在最小的介面上。
(1)介面隔離原則的目的是系統解開耦合,從而容易重構、更改和重新部署。

有些書把5,6併為下面原則:
合成聚合複用原則(CARP):又稱合成複用原則(CRP)。是指在一個新的物件中使用原來已經存在的一些物件,使這些原來已經存在的物件成為新物件的一部分,新的物件通過向這些原來已經具有的物件委派相應的動作或者命令達到複用已有功能的目的。
(1)簡潔的表述:要儘量使用合成和聚合,儘量不要使用繼承。
(2)聚合是關聯關係的一種,用來表示一種整體和部分的擁有關係。整體持有對部分的引用,可以呼叫部分的能夠被訪問的方法和屬性等;作為部分可以同時被多個新的物件引用,同時為多個新的物件提供服務。
(3)合成也是關聯關係的一種,但比聚合強得多。在合成關係裡,部分和整體的生命週期是一樣的。作為整體的新物件是完全擁有對作為部分的支配權。一個合成關係中的成員物件是不能和另外的一個合成關係 共享的。

二、設計模式
1、簡單工廠模式:屬於類的創新型模式,又稱靜態工廠方法模式,通過專門定義一個類來負責建立其他類的例項,被建立的例項通常都具有共同的父類。
(1)包含的角色及其職責:
A、工廠角色:這是簡單工廠模式的核心,由它負責建立所有類的核心邏輯。能夠被外界呼叫,建立所需的產品物件。
B、抽象產品角色:簡單工廠模式所建立的所有物件的父類(可以是介面也可以是抽象類),負責描述所有例項所共有的公共介面。
C、具體產品角色:簡單工廠所建立的具體例項物件。
(2)核心思想:有一個專門的類來負責建立例項的過程。
(3)優缺點
優點:使用者無需瞭解物件是如何建立及如何組織的,有利於整個軟體體系結構的優化。
缺點:違背單一職責原則和開放封閉原則。
(4)android中簡單工廠模式之一就是獲取服務的系統方法“getSystemService”
(5)實質是選擇實現的過程。
2、工廠方法模式:同樣屬於類的建立型模式,又稱多型工廠模式。意義是定義一個建立產品物件的工廠介面,將實際建立工作推遲到子類中。
(1)包含的角色及其職責:
A、抽象工廠角色:這是工廠方法模式的核心,任何工廠類都必須實現這個介面。
B、具體工廠角色:具體工廠類是抽象工廠的一個實現,負責例項化產品物件。
C、抽象產品角色:簡單工廠模式所建立的所有物件的父類(可以是介面也可以是抽象類),負責描述所有例項所共有的公共介面。
D、具體產品角色:簡單工廠所建立的具體例項物件。
(2)工廠方法模式解決的是同一系列產品的建立問題。
(3)優缺點
優點:當系統拓展需要新增新的產品物件時,僅需新增一個具體物件以及一個具體工廠物件,原有工廠物件不需修改。很好符合開放封閉原則。
缺點:把簡單工廠模式的內部判斷邏輯轉移到了客戶端,客戶端需要決定例項化哪一個具體的工廠。
(4)android的activity和service等核心元件中都定義了onCreate()方法。

3、抽象工廠模式:是所有形態 的工廠模式中最為抽象和最具一般性的。抽象工廠模式可以向客戶端提供一個介面,使客戶端在不必指定產品型別的情況下,能夠建立多個產品族的產品物件。
(1)包含的角色及其職責:
A、抽象工廠角色:這是工廠方法模式的核心,包含對多個產品結構的宣告,任何工廠類都必須實現這個介面。
B、具體工廠角色:具體工廠類是抽象工廠的一個實現,負責例項化某個產品族中的產品物件。
C、抽象產品角色:抽象模式所建立的所有物件的父類(可以是介面也可以是抽象類),負責描述所有例項所共有的公共介面。
D、具體產品角色:抽象模式所建立的具體例項物件。
(2)工廠方法模式針對的是一個產品等級結構;而抽象工廠模式針對的是多個產品等級結構。
(3)優缺點
優點:客戶端不再負責物件的具體建立,而是把這個任務交給了具體工廠類,客戶端只負責對物件的呼叫。
缺點:新產品加入時,需要修改抽象工廠類的設計,導致要修改所有具體工廠類。
(4)android應用開發中涉及到的IPC通訊就是抽象工廠模式很好的說明。

4、單例模式:是一種物件建立型模式。保證一個類只有一個例項存在,同時提供能對該例項加以訪問的全域性訪問方法。
(1)單例模式的要點:一是某個類只能有一個例項;二是它必須自行建立這個例項;三是它必須自行向整個系統提供這個例項。
(2)單例模式的版本:
A、餓漢式:即當類載入進來時就立即例項化物件,但這種方式比較消耗計算機資源。
B、懶漢式:要使用時才例項化,但多執行緒下存線上程安全問題。
C、在懶漢式的基礎上對函式進行同步的方式。

如何實現懶漢式的執行緒安全?

加上synchronized即可

public static synchronized Singleton getInstance(){}
但這樣會降低整個訪問的速度,而且每次都要判斷。可以用雙重檢查加鎖。

雙重加鎖機制,指的是:並不是每次進入getInstance方法都需要同步,而是先不同步,進入方法過後,先檢查例項是否存在,如果不存在才進入下面的同步塊,這是第一重檢查。進入同步塊後,再次檢查例項是否存在,如果不存在,就在同步的情況下建立一個例項。這是第二重檢查。

雙重加鎖機制的實現會使用一個關鍵字volatile,它的意思是:被volatile修飾的變數的值,將不會被本地執行緒快取,所有對該變數的讀寫都是直接操作共享記憶體,從而確保多個執行緒能正確的處理該變數。

/**

  • 雙重檢查加鎖的單例模式
  • @author dream

*/
public class Singleton {

/**
 * 對儲存例項的變數新增volitile的修飾
 */
private volatile static Singleton instance = null;
private Singleton(){

}

public static Singleton getInstance(){
    //先檢查例項是否存在,如果不存在才進入下面的同步塊
    if(instance == null){
        //同步塊,執行緒安全的建立例項
        synchronized (Singleton.class) {
            //再次檢查例項是否存在,如果不存在才真正的建立例項
           if(instance==null) instance = new Singleton();
        }
    }
    return instance;
}

}

(3)優缺點
優點:只需要呼叫一個單一的方法即可生成一個唯一的例項,有利於節約資源。
缺點:很難實現序列化,導致難以被持久化,難以通過網路傳輸;無法在繼承結構中使用。
(4)android中單例模式無處不在,例如對服務的管理者ServiceManager就採用了單例模式。

5、原型模式:是一種物件建立型模式,它採取負責原型物件的方法來建立物件的例項。使用原型模式建立的例項,具有與原型一樣的初始化資料。
(1)原型模式涉及角色:
A、客戶端角色:客戶端提供建立物件的請求。
B、抽象原型角色:通常由一個java介面或者java抽象類來實現, 為具體原型設立好規範。
C、具體原型角色:被複制的具體物件,此具體角色實現了抽象原型角色所要求實現的方法。
(2)java在語言級別時直接支援原型模式的,java.lang.Object是一切類和介面的父類,它提供了一個clone()方法來支援原型模式。一個有被複制能力的物件要實現Cloneable介面。
複製有淺複製和深複製之分,淺複製是對基本資料型別和string型別而言的,深複製是對其他引用型別而言的。
(3)優缺點
優點:允許動態地增加或減少產品類;提供簡化的建立結構;具有給一個應用軟體動態載入新功能的能力;產品類不需要事先確定等級結構,因為原型模式適用於任何的等級結構。
缺點:每個類都要配備一個複製方法,對已有的類來說不一定容易,對深層的複製也要編寫不少程式碼。

6、建造者模式:又稱生成器模式。是一種物件建立型模式,用來隱藏複合物件的建立過程,它把複合物件的建立過程加以抽象,通過子類繼承和過載的方式,動態地建立具有複合屬性的物件。
(1)建造者模式涉及角色:
A、抽象建造者角色:給出一個抽象介面,以規範產品物件的各個組成成分的建造。
B、具體建造角色:這個角色產品實現了抽象建造者介面,主要完成分步建立產品並提供產品物件的例項。是一些與應用程式緊密相關的一些類。
C、導演者角色:具有指揮使用哪個具體創造者來完成產品的建立,是建立工作的呼叫者。
D、產品角色:就是建造中的複雜物件,一般只有對於複雜物件的建立才使用建造者模式。
(2)建造者模式將複雜物件的構建與物件的表現分離開來,這樣使同樣的構建過程可以創建出不同的表現。
(3)優缺點
優點:客戶端不用再直接負責物件的建立,而是把這些任務交給了具體的建立者類,把具體的如何組裝的責任交給了導演者類,客戶端之負責物件的呼叫即可。
缺點:如果產品差別較大,會導致非常多的具體的建立者。
(4)在android中AlertDialog的構造是建造者模式的一個非常經典的實現。

7、裝飾模式:又稱包裝模式。通過一種對客戶端透明的方式來擴充套件物件的功能,是繼承關係的一個替代方案。
(1)裝飾模式涉及角色:
A、抽象元件角色:一個抽象介面,是被修飾類和修飾類的父介面。
B、具體元件角色:為抽象元件的實現類。
C、抽象裝飾角色:包含一個元件的引用,並定義了與抽象元件一致的介面。
D、具體裝飾角色:為抽象裝飾角色的實現類,負責具體的裝飾。
(2)優缺點
優點:比繼承關係更靈活地擴充套件物件的功能,可以構造出很多種不同種類的修飾結果。
缺點:很多修飾類,產生管理問題;產生不合邏輯的物件;比較容易出錯,且出錯後不易排查。
(3)java的IO庫中很好地使用了這種模式,如DataOutputStream等等。