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