程序設(shè)計幾大原則

一、單一職責(zé)原則(SRP)

單一職責(zé)原則(SRP)用于指導(dǎo)我們令境,在對功能劃分到具體的類中的時候杠园,要保證具有高內(nèi)聚性。對于SRP的一個很好的描述是:就一個類而言舔庶,應(yīng)該僅有一個引起它變化的原因抛蚁。

想要使用好SRP,一個首先要搞清楚的問題是:什么是職責(zé)栖茉?每一個職責(zé)都是變化的一個軸線篮绿,職責(zé)被定義為"變化的原因"。

這里對于職責(zé)的定義個人感覺比較清楚明確吕漂。我們要知道亲配,SRP中的職責(zé)并不是一個類中的函數(shù),而是一個變化的軸線惶凝,具體到不同層次的類吼虎,其職責(zé)有大有小。如對于一個Activity來說苍鲜,其負責(zé)的是展示一個完整的界面思灰,那么界面的內(nèi)容獲取勢必從他里面發(fā)起,界面的數(shù)據(jù)處理勢必在其里面完成混滔,一個Activity里面做的事情洒疚,調(diào)用的方法有很多,但是站在其層次的角度來考慮坯屿,一個Activity的職責(zé)就是負責(zé)好他所對應(yīng)的頁面油湖,而其他頁面的事情對它來說就是多余的職責(zé)。

即SRP告訴我們领跛,當(dāng)一個類中某幾個功能常常衍生出新的場景乏德、新的實現(xiàn)方式時,那么應(yīng)該考慮將他們各自進行獨立的職責(zé)封裝吠昭,而不是在當(dāng)前類中不斷的改來改去喊括、加來加去來使得當(dāng)前類變得臃腫、難以維護矢棚。

1郑什、一個例子

舉一個例子,假設(shè)需要裝一臺電腦蒲肋,以下是配置:

public class Computer {
    private String CPU() {
        return "最貴的最好的CPU";
    } 
    private String board(){
        return "最實惠的蹦误、型號對應(yīng)的主板";   
    }
    
    private void build() {
        String cpu = CPU();
        String board = board();
        return "電腦配置為"+cpu+board;
    }
}

當(dāng)前來看這個類很單純劫拢,就是組裝一臺電腦嘛,完全可以勝任强胰,目前的方案是在CPU上花錢舱沧,主板挑一個過得去的就行侠鳄;但是雕崩,不同的人需求不一樣哟绊,有的人追求夠用即可在CPU上也追求實惠桑滩,有的人土豪一個蚂斤,在主板上也追求最貴最好彻犁。這樣的需求變動不得不使我們在Computer類中添加對應(yīng)的方法來滿足以上需求堂污,這樣就導(dǎo)致了Computer類的臃腫和難以維護妒蛇。

上述的問題在于恩脂,在可預(yù)見的未來帽氓,用戶選擇CPU的方案和選擇board的方案都會產(chǎn)生很多變化,即Computer類變化的軸線有兩個:CPU和board俩块,這違反了SRP黎休,所以方案就是將CPU的選擇方案封裝成一個單獨的類CPU,將board的選擇方案封裝成一個單獨的類Board玉凯。同時势腮,這個例子也體現(xiàn)了單一職責(zé)也是分層次的,Computer的職責(zé)是負責(zé)組裝電腦漫仆,CPU的職責(zé)是負責(zé)確定哪款CPU捎拯,Board的職責(zé)是負責(zé)確定哪款主板。

另外盲厌,在上述問題中CPU的選擇方案與主板之間還存在一種約束關(guān)系(型號對不上)署照,因此,如果不將職責(zé)進行拆分的話吗浩,build方法還可能因為耦合關(guān)系建芙,出現(xiàn)運行錯誤的情況,而這種情況當(dāng)代碼量很大時是很難察覺的拓萌。如果進行了職責(zé)的拆分,Computer類只負責(zé)CPU和board方案的匹配校驗工作升略,那么這種錯誤發(fā)生的概率就會降低很多微王。

2. 小結(jié)

通過上述例子我們可以粗略大膽的認為當(dāng)一下情況出現(xiàn)的時候,你的類違背了SRP品嚣,并且到了需要拆分的時候:

  1. 當(dāng)前類包含了多個子功能的具體實現(xiàn)炕倘;
  2. 在應(yīng)用場景中,上述子功能分別會有多種可能的實現(xiàn)方案翰撑。

二罩旋、開放封閉原則(OCP)

開閉原則(OCP):軟件實體應(yīng)該是可擴展的啊央,但是不可修改的。

按照OCP設(shè)計出的模塊具有兩個特征:

  1. 對擴展開放:模塊的行為是可以擴展的涨醋;當(dāng)應(yīng)用的需求改變時瓜饥,可以對模塊進行擴展來滿足新的行為。
  2. 對更改封閉:對模塊進行擴展時浴骂,不必改變模塊的源碼乓土。

上面的兩個特征看起來有些矛盾,不改變源碼怎么進行擴展溯警?實際上OCP要求我們使用抽象來定義行為趣苏,使用具體類來實現(xiàn)行為,擴展也就是說使用新的具體類來擴展行為梯轻;封閉也就是說在使用該行為時使用抽象類對象來囊括不同具體行為食磕,這樣一來就不用了更改源碼了(實際上由于多了個具體類,那么最起碼初始化該具體類對象的地方還是相當(dāng)于修改了源碼喳挑,這是沒法避免的)彬伦。

同時,還有一個重點在于蟀悦,在使用OCP來定義行為的時候媚朦,一定要選擇程序中呈現(xiàn)頻繁變化的那些部分進行抽象;如若不然日戈,那么濫用OCP也會帶來很高的維護成本询张。

小結(jié)

通過上面的說明,我們對OCP可以有一個大概的認知浙炼,即具有如下結(jié)構(gòu)的應(yīng)用:

  1. 定義類時采用抽象類份氧,實例化時采用具體類,即所謂的左類型與右類型弯屈。

三蜗帜、里式替換原則(LSP)

上述的OCP核心思想在于:利用抽象來定義行為,利用具體類來實現(xiàn)和實施不同種的行為资厉。但是厅缺,在面向?qū)ο箝_發(fā)中還有另一種形式的繼承機制,即父類并不是抽象類宴偿,在一些情況下父類可以勝任很多工作湘捎,但有時候需要子類對象來擴展一些工作,而不得不實例化子類對象窄刘,這時候就需要要求在實例化子類對象時窥妇,他要能夠完成其父類角色的任務(wù)。

即:在大多數(shù)情況下Parent a = new Parent();a.fun1();即可完成工作娩践,但有時候需要使用到子類:Parent b = new Child();b.fun1();b.fun2();才能夠完成工作活翩。那么就需要子類的fun1()方法能夠像父類的該方法一樣承擔(dān)應(yīng)有的工作烹骨。

LSP的解釋如下:子類型必須能夠替換掉他們的基類型。并且在替換掉基類型之后材泄,程序依然能夠運行沮焕。

1. 一個例子

假設(shè)父類的sort函數(shù)可以實現(xiàn)對數(shù)組的升序排序:

class Parent {
    int[] array;
    public Parent(int[] a) {
        this.array = a;
    }
    
    public void sort() {
        實現(xiàn)對array的升序排序
        ...
    }
}

class Child {
    ...
    @override  
    public void sort(){
        實現(xiàn)對array的降序排序
    }
}

很顯然,上述的子類雖然是繼承了父類脸爱,并且重寫了父類的sort方法遇汞,但是將全局的所有父類對象的實現(xiàn)變?yōu)樽宇悓ο螅敲闯绦蚩隙〞鰡栴}簿废。這就是LSP所約束的問題空入。

2. 小結(jié)

LSP和OCP看起來都是在說繼承的問題,但是他們所關(guān)注的場景不同族檬,而且可以看出OCP顯然是遵從了LSP的歪赢,因為OCP的背景為不同子類去擴展抽象類所定義的行為的。

而LSP則告訴我們单料,子類在覆蓋父類的方法的時候不能夠任意實現(xiàn)埋凯,而是要遵循父類對該方法的期望與要求。為此扫尖,有人提出了一種契約設(shè)計的方式:

  1. 契約是通過為每一個方法聲明的前置條件和后置條件來指定的白对;
  2. 要使一個方法得以執(zhí)行,前置條件必須要為真换怖;執(zhí)行完畢后甩恼,后置條件必須為真;
  3. 派生類的前置條件和后置條件的規(guī)則為:在重新聲明派生類中的例程時沉颂,只能使用相等或更弱的前置條件來替換基類的前置條件条摸;只能使用相等或更強的后置條件來替換基類的后置條件。

四铸屉、依賴倒置原則(DIP)

開門見山钉蒲,該原則的解釋為:

  1. 高層模塊不應(yīng)該依賴于低層模塊,二者都應(yīng)該依賴于抽象彻坛;
  2. 抽象不應(yīng)該依賴于細節(jié)顷啼,細節(jié)應(yīng)該依賴于抽象。

如果高層模塊依賴于低層模塊昌屉,那么在不同的上下文中重用高層模塊會變得非常困難钙蒙。

首先要明確一點的是,既然是高層模塊怠益,那么其勢必要使用低層模塊提供的功能或者說服務(wù)仪搔,如何做到高層不依賴于低層呢瘾婿?答案就在后半句蜻牢,抽象烤咧,不過要加上一種要求:抽象由高層模塊來定義,低層模塊去實現(xiàn)它抢呆。這樣一來煮嫌,高層模塊就可以通過抽象類對象來使用想要的服務(wù),而不必理會低層模塊是如何實現(xiàn)它的抱虐,從而避免了對低層模塊的依賴昌阿。這也體現(xiàn)了第二個要求,是細節(jié)依賴抽象而不是抽象依賴細節(jié)恳邀,即高層模塊一旦定義了想要的服務(wù)懦冰,就不必理會低層模塊的具體實現(xiàn)方式,即這種服務(wù)一定要抽象到不用去理會實現(xiàn)細節(jié)谣沸。

很明顯刷钢,一個典型的例子就是計算機網(wǎng)絡(luò)協(xié)議的設(shè)計,高層協(xié)議通過服務(wù)訪問點來使用下層協(xié)議所提供的服務(wù)乳附,而不必理會下層協(xié)議是何種協(xié)議内地。例如TCP是傳輸層協(xié)議,其只需要下層能夠?qū)?shù)據(jù)傳輸?shù)蕉思纯筛吵魂P(guān)心你是IPv4還是IPv6.

五阱缓、接口隔離原則(ISP)

接口隔離原則很簡單:

不應(yīng)該強迫客戶依賴于他們不用的方法

因為一旦這些方法發(fā)生變化,他們不得不做出相應(yīng)的改變举农。

很顯然荆针,出現(xiàn)上述情況時,應(yīng)該對接口進行拆分了并蝗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末祭犯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子滚停,更是在濱河造成了極大的恐慌沃粗,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件键畴,死亡現(xiàn)場離奇詭異最盅,居然都是意外死亡,警方通過查閱死者的電腦和手機起惕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門涡贱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惹想,你說我怎么就攤上這事问词。” “怎么了嘀粱?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵激挪,是天一觀的道長辰狡。 經(jīng)常有香客問我,道長垄分,這世上最難降的妖魔是什么宛篇? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮薄湿,結(jié)果婚禮上叫倍,老公的妹妹穿的比我還像新娘。我一直安慰自己豺瘤,他們只是感情好吆倦,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坐求,像睡著了一般逼庞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瞻赶,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天赛糟,我揣著相機與錄音,去河邊找鬼砸逊。 笑死璧南,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的师逸。 我是一名探鬼主播司倚,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼篓像!你這毒婦竟也來了动知?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤员辩,失蹤者是張志新(化名)和其女友劉穎盒粮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奠滑,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡丹皱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了宋税。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摊崭。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖杰赛,靈堂內(nèi)的尸體忽然破棺而出呢簸,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布根时,位于F島的核電站嘿架,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏啸箫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一伞芹、第九天 我趴在偏房一處隱蔽的房頂上張望忘苛。 院中可真熱鬧,春花似錦唱较、人聲如沸扎唾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胸遇。三九已至,卻和暖如春汉形,著一層夾襖步出監(jiān)牢的瞬間纸镊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工概疆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逗威,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓岔冀,卻偏偏與公主長得像凯旭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子使套,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容