1個類只負責1個功能領域中的相應職責,或可以定義為:就1個類而言,應當只有1個引發它變化的緣由。
亞當·斯密曾就制針業做過1個分工產生效力的例子。對1個沒有受過相應訓練,又不知道怎樣使用這類職業機械的工人來說,即便他全力以赴地工作,或許1天連1根針也生產不出來,固然更生產不出20根針了。但是,如果把這個行業分成各種專門的組織,再把這類組織分成許多個部門,其中大部份部門也一樣分為專門的組織。把制針分為18種不同工序,這18種不同操作由18個不同工人來擔負。那末,雖然他們的機器裝備都很差,但他們盡力工作,1天也能生產12磅針。每磅中等型號針有4000根,按這個數字計算,10多個人每天就能夠制造48000根針,而每一個人每天能制造4800根針。如果他們各自獨立地工作,誰也不專學做1種專門的業務,那末他們當中不管是誰都絕不可能1天制造20根針,或許連1根針也制造不出來。這就是企業管理中的分工,在面向對象的設計里,叫做單1職責原則(Single Pesponsibility Principle,SRP)。
在《敏捷軟件開發》中,把“職責”定義為“變化的緣由”,也就是說,就1個類而言,應當只有1個引發它變化的緣由。說的簡單點就是怎樣設計1個類和類的方法界定問題。這類問題很普遍,比如在MVC框架中,很多人會有這樣的疑惑,對表單插入數據庫字段過濾與安全檢查應當是放在control層處理還是model層處理,這類問題可以歸到單1職責的范圍。
單1職責有兩個含義:1個是避免相同的職責分散到不同的類中,另外一個是避免1個類承當太多職責。
可以減少類之間的耦合。
如果減少類之間的耦合,當需求變化時,只修改1個類,從而也就隔離了變化;如果1個類有多個不同職責,它們耦合在1起,當1個職責產生變化時,可能會影響其他職責。
提高類的復用性
修理電腦比修理電視機簡單多了。主要緣由就在于電視機各個部件之間的耦合性太高,而電腦則不同,電腦的內存、硬盤、聲卡、網卡、鍵盤燈部件都可以很容易地單獨拆卸和組裝。某個部件壞了,換上新的便可。
上面的例子就體現了單1職責的優勢。由于使用了單1職責,使得“組件”可以方便地“拆卸”和“組裝”。
不遵照SRP會影響對該類的復用性。當只需要復用該類的某1個職責時,由于它和其他的職責耦合在1起,也就很難分離出。
有的。以數據持久層為例,所謂的數據持久層主要指的是數據庫操作,固然,還包括緩存管理等。以數據庫操作為例,如果是1個復雜的系統,那末便可能觸及多種數據庫的相互讀寫等,這時候就需要數據持久層支持多種數據庫。應當怎樣做?定義多個數據庫操作類?你的想法已很接近了,再進1步,就是使用工廠模式。
工廠模式(Factory)允許你在代碼履行時實例化對象。它之所以被稱為工廠模式是由于它負責“生產”對象。以數據庫為例,工廠需要的就是根據不同的參數,生成不同的實例化對象。最簡單的工廠就是根據傳入的類型名實例化對象,如傳入MySQL,就調用MySQL的類并實例化,如果是SQLite,則調用SQLite的類并實例化,乃至可以處理TXT、Excel等“類數據庫”。工廠類也就是這樣的1個類,它只負責生產對象,而不負責對象的具體內容。
設計模式里面的命令模式也是SRP的體現,命令模式分離“命令的要求者”和“命令的實現者”方面的職責。舉1個很好理解的例子,就是你去餐館吃飯,餐館存在顧客、服務員、廚師3個角色。作為顧客,你只要列出菜單,傳給服務員,由服務員通知廚師去實現。作為服務員,只需要調用準備飯菜這個方法(對廚師大喊“該炒菜了”),廚師聽到要炒菜的要求,就立即去做飯。在這里,命令的要求和實現就完成了解耦。
在設計模式方面,不但以上這兩種體現了SRP,還有別的(比如代理模式)也體現了SRP。SRP不只是對類設計成心義,對以模塊、子系統為單位的系統架構設計一樣成心義。
模塊、子系統也應當唯一1個引發它變化的緣由,如MVC所提倡的各個層之間的相互分離其實就是SRP在系統整體設計中的利用。
根據業務流程,把業務對象提煉出來。如果業務流層的鏈路太復雜,就把這個業務對象分離為多個單1業務對象。當業務鏈標準化后,對業務對象的內部情況做進1步處理。把第1次標準化視為最高層抽象,第2次視為次高層抽象,以此類推,直到“恰如其分”的設計層次。
職責的分類需要注意。有業務職責,還要有脫離業務的抽象職責,從認識業務到抽象算法是1個層層遞進的進程。就好比命令模式中的顧客,服務員和廚師的職責,作為老板(即設計師)的你需要計劃好各自的職責范圍,既要避免越俎代庖,也要避免相互推委。