在做代碼練習(xí)或者開發(fā)的過程中揩悄,我們會(huì)發(fā)現(xiàn)自己寫的類越來越大慷嗜,該類的功能也越來越多穷缤。有一些開發(fā)者包括之前的我看到自己寫的類夠大,功能夠多是往往會(huì)充滿自豪感三椿。但是當(dāng)某個(gè)功能需要做一個(gè)小改動(dòng)時(shí)缺菌,就會(huì)發(fā)現(xiàn)整個(gè)程序出現(xiàn)了各種大大小小的問題。
為什么知識(shí)對(duì)這個(gè)類的一個(gè)功能做了小小的修改就會(huì)引起這么大的問題赋续?因?yàn)槲覀冞`反了單一職責(zé)原則男翰。將多種功能集成在一個(gè)類中,就等于把這些功能耦合了起來纽乱,一個(gè)功能的變化可能會(huì)削弱或者抑制這個(gè)類完成其他職責(zé)的能力蛾绎。而如果想要避免這種現(xiàn)象的發(fā)生,就要盡可能的遵守單一職責(zé)原則鸦列。此原則的核心就是解耦和增強(qiáng)內(nèi)聚性租冠。
1. 解說定義
定義:不要存在多于一個(gè)導(dǎo)致類變更的原因。通俗的說薯嗤,即一個(gè)類只負(fù)責(zé)一項(xiàng)職責(zé)顽爹。
在一個(gè)類中,可以導(dǎo)致類變更的因素最多只能有一個(gè)骆姐。何為類變更呢镜粤?當(dāng)你要改變?cè)擃愔心承┐a時(shí),該類的某些用途或特性會(huì)隨著改變玻褪。
但是無(wú)論你怎么改肉渴,這個(gè)類只有最多一個(gè)用途或特性改變了,而不會(huì)再有其他的改變带射。只有這樣一個(gè)類的改變對(duì)其他使用到該類的模塊影響才會(huì)達(dá)到最低同规。也只有一個(gè)類只實(shí)現(xiàn)一個(gè)功能時(shí)才能做到到這種最小的改變。
2. 問題由來
類T負(fù)責(zé)兩個(gè)不同的職責(zé):職責(zé)P1窟社,職責(zé)P2券勺。當(dāng)由于職責(zé)P1需求發(fā)生改變而需要修改類T時(shí),有可能會(huì)導(dǎo)致原本運(yùn)行正常的職責(zé)P2功能發(fā)生故障灿里。
3. 解決辦法
遵循單一職責(zé)原則关炼。分別建立兩個(gè)類T1、T2钠四,使T1完成職責(zé)P1功能盗扒,T2完成職責(zé)P2功能跪楞。這樣缀去,當(dāng)修改類T1時(shí)侣灶,不會(huì)使職責(zé)P2發(fā)生故障風(fēng)險(xiǎn);同理缕碎,當(dāng)修改T2時(shí)褥影,也不會(huì)使職責(zé)P1發(fā)生故障風(fēng)險(xiǎn)。
4.職責(zé)擴(kuò)散
很多程序員都清楚自己編程時(shí)要遵循單一職責(zé)原則咏雌,但總是在不經(jīng)意間違反了這個(gè)原則凡怎。因?yàn)槟撤N原因,某一職責(zé)需要分化為粒度更細(xì)的多個(gè)職責(zé)了赊抖,這就是職責(zé)擴(kuò)散统倒。
5.例子
public interface ICar {
//品牌
void setPinPai(String pinpai);
void getPinPai();
//顏色
void setColor(String color);
void getColor();
//啟動(dòng)
boolean Start(boolean start);
//停車
boolean Stop(boolean stop);
}
}
從上面例子中,我們不知道這個(gè)接口的具體職責(zé)是什么氛雪,有點(diǎn)模糊不清房匆。車子的品牌和顏色是車子的屬性,而啟動(dòng)和停車是車子的行為报亩,將車子的屬性和行為耦合到一個(gè)接口中浴鸿,給人一種結(jié)構(gòu)職責(zé)不清的感覺,對(duì)后期的維護(hù)帶來一定的麻煩弦追。
為了解決這個(gè)問題岳链,應(yīng)當(dāng)使用單一職責(zé)原則,將車子接口中的業(yè)務(wù)對(duì)象(屬性)和業(yè)務(wù)邏輯(行為)解耦劲件,分成兩個(gè)接口掸哑,如下:
/**
* BO:Bussiness Object,業(yè)務(wù)對(duì)象
* 負(fù)責(zé)車子的屬性
* @author 葉漢偉
*/
public interface ICarBO {
//品牌
void setPinPai(String pinpai);
void getPinPai();
//顏色
void setColor(String color);
void getColor();
}
/**
* BL:Business Logic,業(yè)務(wù)邏輯
* 負(fù)責(zé)車子的行為
* @author 葉漢偉
*/
public interface ICarBL {
//啟動(dòng)
boolean Start(boolean start);
//停車
boolean Stop(boolean stop);
}
這樣就實(shí)現(xiàn)了接口的單一職責(zé)原則零远。他們各自有一個(gè)實(shí)現(xiàn)類CarBO苗分、CarBL。當(dāng)需要修改車子屬性的時(shí)候只需要對(duì)CarBO這個(gè)接口來修改遍烦,只會(huì)影響到CarBO這個(gè)類俭嘁,不會(huì)影響其他類。
6. 優(yōu)點(diǎn)
- 可以使得類的邏輯變得簡(jiǎn)單服猪,功能清晰供填。每個(gè)類只負(fù)責(zé)一個(gè)職責(zé),那么這個(gè)類的功能是非常清晰的罢猪,相比于有多個(gè)職責(zé)的類近她,單一職責(zé)的類的邏輯會(huì)更簡(jiǎn)單。
- 程序的可讀性和可維護(hù)性相對(duì)較強(qiáng)膳帕。
- 降低變更引起的風(fēng)險(xiǎn)粘捎,對(duì)系統(tǒng)擴(kuò)展性和維護(hù)性很有幫助薇缅。
但是,單一職責(zé)原則有時(shí)候會(huì)給我們帶來一些麻煩攒磨。如果職責(zé)太多的話泳桦,每個(gè)職責(zé)一個(gè)類,會(huì)造成類的數(shù)量過多娩缰,反而降低了代碼的可讀性和程序的可維護(hù)性灸撰。所以使用這個(gè)職責(zé)的時(shí)候還要具體情況具體分析。建議就是接口一定要采用單一職責(zé)原則拼坎,實(shí)現(xiàn)類的設(shè)計(jì)上盡可能做到單一職責(zé)原則浮毯,最好是一個(gè)原因引起一個(gè)類的變化。