程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 深一層看單一職責原則

深一層看單一職責原則

編輯:關於.NET

單一職責原則(Single Responsibility Principle, SRP)是Bob大叔提倡的S.O.L.I.D五大 設計原則中的第一個。其中,職責(Responsibility)被表述為“變化的原因” (reason to change);SRP被表述為“一個類應該有且只有一個變化的原因”。但如果光從字面去理解, SRP很容易讓人望文生義產生誤解。本文希望能闡明SRP 的本質,達到避免誤解和指導設計的 目的。

動機

對於設計原則的理解應該首先從它的動機入手,即遵循這個原則帶來的好處是什麼?對於 SRP來講,如果遵循“一個類應該有且只有一個變化的原因”是因,那麼“任何一個變化只會 影響一個類”就是果。可見SRP的動機主要是系統的可維護性,即降低適應變化的成本。

多功能與單變化

對於單功能的類來講,比較容易遵循SRP,比如:把string轉換為DateTime類型的工具類 。理解SRP的難點在於在多功能類的情形,即不容易理解多功能與單變化的矛盾。讓我們先來 看一個Modem類的例子,Modem具有4個功能:撥號,掛斷,發送數據,接收數據:

class Modem {
     public void Dial(string aPno) {…}
     public void Hangup() {…}
     public void Send(char aData) {…}
     public char Receive() {…}
}

我們先來考察一下Modem類的變化點,並將其分為兩類:1.Modem類的內部細節變化,比如 Dial、Hangup、Send、Receive等具體實現發生了變化;2.Modem類整體性的變化,比如Modem 類需要增加Poweron和Poweroff方法。上面的Modem類具有多個變化點,不符合SRP。

抽象與抽象層次

但是,需要注意的是上面的Modem類其實是很符合現實的概念模型的,Modem本身就應該具 有這幾個功能點。難道要把Modem類強行拆開嗎,難道所有類都只應該有一個方法嗎?是什麼 原因導致符合現實概念模型的Modem類設計與SRP不符合呢?問題在於抽象與抽象層次,Modem 類是現實概念模型的抽象沒有錯,但是Modem類缺乏抽象層次,低層概念與高層概念混雜,這 正是問題所在。下面是重構以後的Modem類:

interface IDialable{
     void Dial(string aPno);
}
class Dialer : IDialable{
     public void Dial(string aPno){…}
}

class Modem{
     public void Dial(string aPno) { m_dialer.Dial(aPno); }
     private IDialable m_dialer;

     … //hangup, send, receive類似
}

上面的設計將各個功能點抽象為單一的接口,將變化封裝在穩定的接口背後,再通過組合 的方式建立起整體的Modem類與局部的功能點的聯系。這樣就避免了低層的變化傳導到高層。

總結

可見,理解SRP的關鍵在於理解類的抽象層次,高層次的類是高層概念的抽象,低層次的 類是低層概念的抽象。低層的變化只影響低層類,高層的變化只影響高層類。對於遵守SRP的 設計,一定具有很好的抽象層次,因此不妨以SRP為指導和檢驗,幫助我們設計出好的類來。 最後,我用幾個關鍵詞梳理SRP的脈絡:

類只有一個變化的原因 >> 一個變化只影響一個類 >> 變化只影響其相應層 次的類

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved