GRASP(General Responsibility Assignment Software Pattern)是通用職責分配軟件設計模式。
它由《UML和模式應用》(Applying UML and Patterns)一書做者Craig Larman提出。在面向對象設計的過程當中通常的通用方式是構思對象的職責、角色和協做。一般來講,咱們在編碼過程當中先分析問題域,從中抽象出對象解決問題。簡單的面向對象和優良的面向對象設計的區別在於將如何更合理的劃分對象的角色,給對象賦予合理的職責以及對象之間的交互關係。html
在我所理解的GRASP九大原則、SOLID七大原則、GOF23種設計模式這三類設計原則模式中。GRASP處於最上層,SOLID基於它再進一步細化闡述,GOF再根據這些原則進一步的概括出更具體的模式。 GoF模式是針對特定問題而提出的解決方案,而GRASP站在一個更高的角度來看待面向對象軟件的設計,它是GoF設計模式的基礎。GRASP是對象職責分配的基本原則,其核心思想是職責分配,用職責設計對象。數據庫
若是某個類擁有執行某個職責所必需的的信息的話,那麼將這個職責分配給這個類。編程
當咱們不肯定某個職責該分配給類A仍是類B的時候,咱們能夠遵循這個原則。這個設計原則和單一設計原則不一樣,單一職責原則考慮的是單個類中的職責是否都屬於一類職責。而信息專家模式考慮則是該把該同一類職責放進類A仍是類B中。假設咱們有一個長方形Rectangle類(類中有width和height屬性)和一個Measure類,咱們應該把getArea()方法放進Rectangle中去,仍是將width和height參數傳給Measure類,在Measure中實現getArea()呢?依照該準則,既然Rectangle方法已經有了實現getArea()所必須的屬性的話,那麼就把該把getArea()方法放進Retangle類中。同理若是有一個計算屬性呢?假設是長寬高比例widthHeightRatio的話,也遵循該原則。==這個原則和DDD設計思想當中的充血模型是一致的,你們能夠了解一下。==設計模式
若是符合下面的一個或者多個條件,則可將建立類A實例的職責分配給類B編碼
在面向對象的設計當中,沒法避免去建立對象。假設對象B建立對象A,那麼對象B就產生了與對象A的耦合。而這種耦合是沒法消除的,即便你將建立對象A的職責分配給對象C,這種耦合仍是存在的,只是從對象B轉移到對象C上,系統內仍是依然存在這個耦合,沒法避免。那麼當咱們沒法消除耦合的時候,咱們應該考慮的是如何下降這個耦合的耦合度。這個原則給出了指導方針。以上的幾個條件潛在的代表了,其實B已經對A有了耦合,既然B已經存在了對A的耦合,那麼咱們不妨再將建立A的職責分配給他。這樣分配的話,系統內僅存在一個A與B的耦合。若是將建立A的職責分配給C的話,那麼系統內就會存在B與A(B包含A、B頻繁使用A等條件)和C與A這兩個耦合。在JDK的Map中Entry類的建立職責就分配給了持有它的Map。還有一個比較經典的例子就是Order建立SKU。設計
耦合是評價一個系統中各個元素(類、模塊、子系統)之間依賴的程度,而良好的設計應該儘量下降這個程度。
如下是一些耦合關係的體現:orm
在以上的這些耦合條件中,出現得越多表明耦合程度越高。這些條件簡單籠統的來講就是A對B的「感知」。這種感知體如今對象屬性、方法參數、方法返回值以及接口上面。高耦合的類過多地依賴其餘類,這種設計將會致使:一個類的修改致使其餘類產生較大影響,系統難以維護和理解。在重用一個高耦合的類時不得不重用它所依賴的其餘類,系統重用性差。如何下降耦合的程度有如下一些方法:儘可能減小對其餘類的引用,提升方法和屬性的訪問權限,儘可能使用組合/聚合原則來替代繼承。 其實面向對象編程中的多態就是一種下降類型耦合的方法,若是沒有多態的話,咱們的方法須要知道全部子類類型,而多態的話只須要知道父類便可。下降了類型耦合。htm
即功能性緊密相關的職責應該放在一個類裏,並共同完成有限的功能。這點與SOLID原則當中的單一職責和接口隔離是一致的。對象
很直觀的例子就是,若是類的功能都是高內聚並職責單一的,類的複雜性就下降了,複雜性下降致使維護的成本也就下降了。在傳統的Dao設計模式當中,咱們應該儘可能拆分細粒度職責單一的Dao供Service進行調用。在Service當中,哪一類的數據操做調用哪個Dao就顯而易見,而且單個Dao不會太過膨脹致使維護性變差。高內聚也表明了高隔離,高隔離就意味着,在修改某一個方法的時候,不至於影響到太多其餘類。繼承
把接收或者處理系統事件消息的職責分配給一個類。這個類能夠表明:整個系統、設備或者子系統;系統事件發生時對應的用例場景,在相同的用例場景中使用相同的控制器來處理全部的系統事件。
一個控制器是負責接收或者處理事件的組件對象。MVC模式中的C就是控制器模式。而一個控制器應該處理一類事件。例如咱們項目中常常會有的UserController就承擔添加用戶,刪除用戶的事件。一個子系統須要定義多個控制器,分別對應不一樣的事件處理。通常來講,控制器應當把要完成的功能委託給Service或者其餘業務處理對象,它只負責協調和控制業務流程,儘可能不要包含太多業務邏輯。
當相關選擇或行爲隨類型(類)變化而變化時,用多態操做爲行爲變化的類型分配職責。
在面向對象的設計當中常常要根據對象的類型來進行對應的操做。假設咱們有一個畫圖Draw類,有多個圖形類Rectangle、Circle、Square。若是要按照不一樣圖形類進行繪製的話,就須要在Draw類的方法中使用if-else的程序結構,依次判斷類型進行繪製。若是新增一個圖形類的話,就又須要對這段代碼進行更改。這就違反了開閉原則。而採用多態的形式,將繪製的具體步驟交給圖形類的子類實現。就不用使用if-else的程序結構,在新增圖形類的時候也不須要修改Draw類。經過引入多態,子類對象能夠覆蓋父類對象的行爲,更好地適應變化。策略模式、工廠方法模式就是關於多態比較好的例子。
將一組高內聚的職責分配給一個虛構的或處理方便的「行爲」類,它並非問題域中的概念,而是虛構的事物,以達到支持高內聚、低耦合和複用。
OO設計中的領域模型是對領域內的概念或現實世界中的對象的模型化表示。建立領域模型的關鍵思想是減少軟件人員的思惟與軟件模式之間的表示差別。所以,在OO設計時,系統內的大多數類都是來源於現實世界中的真實類。然而,在給這些類分配職責時,有可能會遇到一些很難知足低耦合高內聚的設計原則。純虛構模式對這一問題給出的方案是:給人爲製造的類分配一組高內聚的職責,該類並不表明問題領域的概念,而表明虛構出來的事物。比較明顯的一個例子就是適配器模式,經過虛構出適配器這麼一個概念來解耦兩個對象之間的耦合。
許多項目都須要對數據庫進行操做,將系統中的一些對象進行持久化。信息專家模式給出的建議是將持久化的職責分配給具體的每個模型類。可是這種建議已經被證實是不符合高內聚低耦合原則的。因而,如今的作法每每會在項目中加入相似於DAO或者Repository這樣的類。這些類在領域模型中是並不存在的。
分配職責給中間對象以協調組件或服務之間的操做,使得它們不直接耦合。中間對象就是在其餘組件之間創建的中介。
「中介」簡單來講就是經過一箇中間人來處理一件事。原本直接聯繫的兩個對象能夠經過另外一箇中間對象進行交互,這樣作便實現了隔離和解耦,一個對象的變更不會影響另外一個對象,僅會影響到中間對象。在設計模式當中的適配器模式,橋接模式都採用了一箇中間對象來進行解耦。
找出預計有變化或不穩定的元素,爲其建立穩定的「接口」而分配職責。
受保護變化模式簡稱PV,它是大多數編程和設計的基礎,是模式的基本動機之一,它使系統可以適應和隔離變化。它與面向對象設計原則中的開閉原則相對應,即在不修改原有元素(類、模塊、子系統或系統)的前提下擴展元素的功能。一個比較顯而易見的例子就是策略模式,經過建立策略接口並定義其中的抽象方法來應對可能出現的新策略。未來有新的策略的時候不須要改變原代碼,而是新建實現策略接口的類。