GRASP模式

Liuwei-Sunny發表於2012-09-16

      GRASP,全稱為General Responsibility Assignment Software Pattern,即通用職責分配軟體模式,它由《UML和模式應用》(Applying UML and Patterns)一書作者Craig Larman提出。與其將它們稱之為設計模式,不如稱之為設計原則,因為它是站在物件導向設計的角度,告訴我們怎樣設計問題空間中的類與分配它們的行為職責,以及明確類之間的相互關係等,而不像GoF模式一樣是針對特定問題而提出的解決方案。因此GRASP站在一個更高的角度來看待物件導向軟體的設計,它是GoF設計模式的基礎。

       GRASP物件職責分配的基本原則,其核心思想是職責分配(Responsibility Assignment),用職責設計物件(Designing Objects with Responsibilities)它包含如下9個基本模式:

 

      1. 資訊專家模式 (Information Expert Pattern)

      (1) 問題:給物件分配職責的通用原則是什麼?

      (2) 解決方案:將職責分配給擁有履行一個職責所必需資訊的類,即資訊專家。

      (3) 分析:資訊專家模式是物件導向設計的最基本原則。通俗點來講,就是一個類只幹該乾的事情,不該乾的事情不幹。在系統設計時,需要將職責分配給具有實現這個職責所需要資訊的類。資訊專家模式對應於物件導向設計原則中的單一職責原則。

 

      2. 創造者模式 (Creator Pattern)

      (1) 問題:誰應該負責產生類的例項?

      (2) 解決方案:如果符合下面的一個或者多個條件,則可將建立類A例項的職責分配給類B

  • B包含A
  • B聚合A
  • B擁有初始化A的資料並在建立類A的例項時將資料傳遞給類A
  • B記錄A的例項;
  • B頻繁使用A

      此時,我們稱類B是類A物件的建立者。如果符合多個條件,類B聚合或者包含類A的條件優先。

      (3) 分析:建立物件是物件導向系統中最普遍的活動之一,因此,確定一個分配建立物件的通用職責非常重要。如果職責分配合理,設計就能降低耦合,提高設計的清晰度、封裝性和重用性。通常情況下,如果物件的建立過程不是很複雜,則根據上述原則,由使用物件的類來建立物件。但是如果建立過程非常複雜,而且可能需要重複使用物件例項或者需要從外部注入一個物件例項,此時,可以委託一個專門的工廠類來輔助建立物件。建立者模式與各種工廠模式(簡單工廠模式、工廠方法模式和抽象工廠模式)相對應。

 

      3. 低耦合模式 (Low Coupling Pattern)

      (1) 問題:怎樣支援低的依賴性,減少變更帶來的影響,提高重用性?

      (2) 解決方案:分配一個職責,使得保持低耦合度。

      (3) 分析:耦合是評價一個系統中各個元素之間連線或依賴強弱關係的尺度,具有低耦合的元素不過多依賴其他元素。此處的元素可以是類,也可以是模組、子系統或者系統。具有高耦合的類過多地依賴其他類,這種設計將會導致:一個類的修改導致其他類產生較大影響;系統難以維護和理解;系統重用性差,在重用一個高耦合的類時不得不重用它所依賴的其他類。因此需要對高耦合的系統進行重構。

      類A和類B之間的耦合關係體現如下:A具有一個B型別的屬性;A呼叫B的方法;A的方法包含對B的引用,如方法引數型別為B或返回型別為BAB的直接或者間接子類;B是一個介面,A實現了該介面。低耦合模式鼓勵在進行職責分配時不增加耦合性,從而避免高耦合可能產生的不良後果。在進行類設計時,需要保持類的獨立性,減少類變更所帶來的影響,它通常與資訊專家模式和高內聚模式一起出現。為了達到低耦合,我們可以通過如下方式對設計進行改進:

  • 在類的劃分上,應當儘量建立鬆耦合的類,類之間的耦合度越低,就越有利於複用,一個處在鬆耦合中的類一旦被修改,不會對關聯的類造成太大波及;
  • 在類的設計上,每一個類都應當儘量降低其成員變數和成員函式的訪問許可權;
  • 在類的設計上,只要有可能,一個型別應當設計成不變類;
  • 在對其他類的引用上,一個物件對其他物件的引用應當降到最低。

      4. 高內聚模式 (High Cohesion Pattern)

      (1) 問題:怎樣使得複雜性可管理?

     (2) 解決方案:分配一個職責,使得保持高內聚。

      (3) 分析:內聚是評價一個元素的職責被關聯和關注強弱的尺度。如果一個元素具有很多緊密相關的職責,而且只完成有限的功能,則這個元素就具有高內聚性。此處的元素可以是類,也可以是模組、子系統或者系統。

      在一個低內聚的類中會執行很多互不相關的操作,這將導致系統難於理解、難於重用、難於維護、過於脆弱,容易受到變化帶來的影響。因此我們需要控制類的粒度,在分配類的職責時使其內聚保持為最高,提高類的重用性,控制類設計的複雜程度。為了達到低內聚,我們需要對類進行分解,使得分解出來的類具有獨立的職責,滿足單一職責原則。在一個類中只保留一組相關的屬性和方法,將一些需要在多個類中重用的屬性和方法或完成其他功能所需的屬性和方法封裝在其他類中。類只處理與之相關的功能,它將與其他類協作完成複雜的任務。

 

      5. 控制器模式 (Controller Pattern)

      (1) 問題:誰應該負責處理一個輸入系統事件?

      (2) 解決方案:把接收或者處理系統事件訊息的職責分配給一個類。這個類可以代表:

  • 整個系統、裝置或者子系統;
  • 系統事件發生時對應的用例場景,在相同的用例場景中使用相同的控制器來處理所有的系統事件。

      (3) 分析:一個控制器是負責接收或者處理系統事件的非圖形使用者介面物件。一個控制器定義一組系統操作方法。在控制器模式中,要求系統事件的接收與處理通常由一個高階類來代替;一個子系統需要定義多個控制器,分別對應不同的事務處理。通常,一個控制器應當把要完成的功能委託給其他物件,它只負責協調和控制,本身不完成太多的功能。它可以將使用者介面所提交的請求轉發給其他類來處理,控制器可以重用,且不能包含太多業務邏輯,一個系統通常也不能設計一個統一的控制器。控制器模式與MVC模式相對應,MVC是一種比設計模式更加高階的架構模式。  

 

      6. 多型模式 (Polymorphism Pattern)

      (1) 問題:如何處理基於型別的不同選擇?如何建立可嵌入的軟體元件?

      (2) 解決方案:當相關選擇或行為隨型別(類)變化而變化時,用多型操作為行為變化的型別分配職責。

      (3) 分析:由條件變化引發同一型別的不同行為是程式的一個基本主題。如果用if-elseswitch-case等條件語句來設計程式,當系統發生變化時必須修改程式的業務邏輯,這將導致很難方便地擴充套件有新變化的程式。另外對於伺服器/客戶端結構中的視覺化元件,有時候需要在不影響客戶端的前提下,將伺服器的一個元件替換成另一個元件。此時可以使用多型來實現,將不同的行為指定給不同的子類,多型是設計系統如何處理相似變化的基本方法,基於多型分配職責的設計可以方便地處理新的變化。在使用多型模式進行設計時,如果需要對父類的行為進行修改,可以通過其子類來實現,不同子類可以提供不同的實現方式,將具體的職責分配給指定的子類。新的子類增加到系統中也不會對其他類有任何影響,多型是物件導向的三大基本特性之一(另外兩個分別是封裝和繼承),通過引入多型,子類物件可以覆蓋父類物件的行為,更好地適應變化,使變化點能夠“經得起未來驗證”。多型模式在多個GoF設計模式中都有所體現,如介面卡模式、命令模式、組合模式、觀察者模式、策略模式等等。

 

      7. 純虛構模式 (Pure Fabrication Pattern)

      (1) 問題:當不想破壞高內聚和低耦合的設計原則時,誰來負責處理這種情況?

      (2) 解決方案:將一組高內聚的職責分配給一個虛構的或處理方便的“行為”類,它並不是問題域中的概念,而是虛構的事務,以達到支援高內聚、低耦合和重用的目的。

      (3) 分析:純虛構模式用於解決高內聚和低耦合之間的矛盾,它要求將一部分類的職責轉移到純虛構類中,在理想情況下,分配給這種虛構類的職責是為了達到高內聚和低耦合的目的。在實際操作過程中,純虛構有很多種實現方式,例如將資料庫操作的方法從資料庫實體類中剝離出來,形成專門的資料訪問類,通過對類的分解來實現類的重用,新增加的資料訪問類對應於資料持久化儲存,它不是問題域中的概念,而是軟體開發者為了處理方便而產生的虛構概念。純虛構可以消除由於資訊專家模式帶來的低內聚和高耦合的壞設計,得到一個具有更好重用性的設計。在系統中引入抽象類或介面來提高系統的擴充套件性也可以認為是純虛構模式的一種應用。純虛構模式通常基於相關功能的劃分,是一種以功能為中心的物件或行為物件。在很多設計模式中都體現了純虛構模式,例如介面卡模式、策略模式等等。

 

      8. 中介模式 (Indirection Pattern)

     (1) 問題:如何分配職責以避免兩個(或多個)事物之間的直接耦合?如何解耦物件以降低耦合度並提高系統的重用性?

     (2) 解決方案:分配職責給中間物件以協調元件或服務之間的操作,使得它們不直接耦合。中間物件就是在其他元件之間建立的中介。

      (3) 分析:要避免物件之間的直接耦合,最常用的做法是在物件之間引入一箇中間物件或中介物件,通過中介物件來間接相連。中介模式對應於物件導向設計原則中的迪米特法則,在外觀模式、代理模式、中介者模式等設計模式中都體現了中介模式。

 

      9. 受保護變化模式 (Protected Variations Pattern)

      (1) 問題:如何分配職責給物件、子系統和系統,使得這些元素中的變化或不穩定的點不會對其他元素產生不利影響?

      (2) 解決方案:找出預計有變化或不穩定的元素,為其建立穩定的“介面”而分配職責。

      (3) 分析:受保護變化模式簡稱PV,它是大多數程式設計和設計的基礎,是模式的基本動機之一,它使系統能夠適應和隔離變化。它與物件導向設計原則中的開閉原則相對應,即在不修改原有元素(類、模組、子系統或系統)的前提下擴充套件元素的功能。開閉原則又可稱為“可變性封裝原則(Principle of Encapsulation of Variation, EVP)”,要求找到系統的可變因素並將其封裝起來。如將抽象層的不同實現封裝到不同的具體類中,而且EVP要求儘量不要將一種可變性和另一種可變性混合在一起,這將導致系統中類的個數急劇增長,增加系統的複雜度。在具體實現時,為了符合受保護變化模式,我們通常需要對系統進行抽象化設計,定義系統的抽象層,再通過具體類來進行擴充套件。如果需要擴充套件系統的行為,無須對抽象層進行任何改動,只需要增加新的具體類來實現新的業務功能即可,在不修改已有程式碼的基礎上擴充套件系統的功能。大多數設計原則和GoF模式都是受保護變化模式的體現。

【作者:劉偉  http://blog.csdn.net/lovelion

相關文章