SRP——單一職責原則

轉載: http://map.110100.cn/00118/35643.htm

 面向對象設計五大原則的理解,他們分別是:SRP——單一職責原則;OCP——開放封閉原則;LSP——Liskov替換原則;DIP——依賴倒置原則;ISP——接口隔離原則。

 

1.   單一職責原則

 

在《敏捷軟件開發》中,把“職責”定義爲“變化的原因”,也就是說,就一個類而言,應該只有一個引起它變化的原因。

 

在《UML與模式應用》一書中又提到,“職責”可以定義爲“一個類或者類型的契約或者義務”,並把職責分成“知道”型職責和“做”型職責。

 

其中“做”型職責指的是一個對象自己完成某種動作或者和其他對象協同完成某個動作;“知道”型職責指的是一個對象需要了解哪些信息。如果按照這種方式來定義“職責”的話,就與《敏》中對單一職責原則的定義不太相符了,所以還是理解爲“變化的原因”比較恰當。

 

這個原則很好理解,但是既然談到了職責,就不妨再來看看GRASP——通用職責分配軟件模式(選自《UML與模式應用》)。按照我自己的看法來講,在下面這些職責分配模式中所涉及到的設計問題,是建立在現實世界抽象層次上的設計,從這個層次上進一步細化,纔到了設計模式所說的針對接口編程和優先使用組合的兩大原則。

 

在這個層次上的抽象,一定要按照現實生活中的思維方法來進行,從我們人類考慮問題的角度出發,把解決現實問題的思維方式逐漸轉化成程序能夠理解的思維方式,絕不允許在這一步考慮程序代碼如何實現,那樣子的架構就是基於程序實現邏輯,而不是從解決問題的角度出發來實現業務邏輯(參考“面向對象的思維方法”)。

 

1)   專家模式。

 

在一個系統中可能存在成千上萬個職責,在面向對象的設計中,定義對象的交互時,就要做出如何將職責分配給類的設計選擇。

 

專家模式的解決方案就是:把一個職責分配給信息專家——掌握了爲履行職責所必需的信息的類。

 

按照專家模式可以得到:一個對象所執行的操作通常是這個對象在現實世界中所代表的事物所執行的操作——這恰恰印證了我上面中的說法。

 

不過使用專家模式的時候,一定要仔細判斷什麼樣的職責是應該只由一個類完成,什麼樣的職責應該由不同的類協作完成。舉一個小小的反例吧,在“思維方法”一文中,提供了一個收發郵件的例子用以說明作者的觀點,源碼如下所示:

public class JunkMail {

private String head;

private String body;

private String address;

public JunkMain() { // 默認的類構造器

this.head=...;

this.body=...;

}

public static boolean sendMail(String address) {

// 調用qmail,發送email

}

public static Collection listAllMail() {

// 訪問數據庫,返回一個郵件地址集合

}

}

作者在這裏就犯了一個職責分配的錯誤:上面的headbodyaddress都是屬於郵件自身的屬性,但是這個類卻有一個叫做sendMail的方法,錯誤就在這個方法這裏。在現實生活中,我們發送郵件的時候,是通過郵遞員來進行的,絕對沒有一封信會長上翅膀自己飛到收信人的手中,在程序中也是一樣,一封郵件絕不可能自己把自己發送出去,應該通過某個MailController之類的類來完成這個功能(之所以不命名爲MailSender,是因爲後面可能還要添加receiveMail等功能)。

 

2)    創建者模式

 

   如果下列條件滿足的話,就把創建類A的實例的職責分配給類B的實例:

a)        B聚集了A對象

b)        B包含了A對象

c)        B記錄了A對象的實例

d)        B要經常使用A對象

e)        A的實例被創建時,B具有要傳遞給A的初始化數據(也就是說B是創建A的信息專家)

如果以上條件中不止一條滿足的話,那麼最好讓B聚集或者包含A

 

創建者模式用於指導對象實例創建任務的分配,基本目的就是找到一個與被創建對象有關聯關係的創建者。

 

3)    低耦合度

4)    高聚合度

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章