面向?qū)ο蟮牧蠡驹瓌t

轉(zhuǎn)載自面向?qū)ο蟮牧蠓▌t

這是設(shè)計模式系列開篇的第一篇文章溉卓。也是我學習設(shè)計模式過程中的總結(jié)懂从。這篇文章主要講的是面向?qū)ο笤O(shè)計中败京,我們應(yīng)該遵循的六大原則艰垂。只有掌握了這些原則泡仗,我們才能更好的理解設(shè)計模式。
我們接下來要介紹以下6個內(nèi)容材泄。

  1. 單一職責原則——SRP
  2. 開閉原則——OCP
  3. 里式替換原則——LSP
  4. 依賴倒置原則——DIP
  5. 接口隔離原則——ISP
  6. 迪米特原則——LOD

單一職責原則

單一職責原則的定義是就一個類而言沮焕,應(yīng)該僅有一個引起他變化的原因吨岭。也就是說一個類應(yīng)該只負責一件事情拉宗。如果一個類負責了方法M1,方法M2兩個不同的事情,當M1方法發(fā)生變化的時候,我們需要修改這個類的M1方法旦事,但是這個時候就有可能導致M2方法不能工作魁巩。這個不是我們期待的,但是由于這種設(shè)計卻很有可能發(fā)生姐浮。所以這個時候谷遂,我們需要把M1方法,M2方法單獨分離成兩個類卖鲤。讓每個類只專心處理自己的方法肾扰。
單一職責原則的好處如下:

  1. 可以降低類的復雜度,一個類只負責一項職責蛋逾,這樣邏輯也簡單很多
  2. 提高類的可讀性集晚,和系統(tǒng)的維護性,因為不會有其他奇怪的方法來干擾我們理解這個類的含義
  3. 當發(fā)生變化的時候区匣,能將變化的影響降到最小偷拔,因為只會在這個類中做出修改。

開閉原則

開閉原則和單一職責原則一樣亏钩,是非沉拢基礎(chǔ)而且一般是常識的原則。開閉原則的定義是軟件中的對象(類姑丑,模塊蛤签,函數(shù)等)應(yīng)該對于擴展是開放的,但是對于修改是關(guān)閉的栅哀。
當需求發(fā)生改變的時候顷啼,我們需要對代碼進行修改,這個時候我們應(yīng)該盡量去擴展原來的代碼昌屉,而不是去修改原來的代碼钙蒙,因為這樣可能會引起更多的問題。
這個準則和單一職責原則一樣间驮,是一個大家都這樣去認為但是又沒規(guī)定具體該如何去做的一種原則躬厌。
開閉原則我們可以用一種方式來確保他,我們用抽象去構(gòu)建框架竞帽,用實現(xiàn)擴展細節(jié)扛施。這樣當發(fā)生修改的時候,我們就直接用抽象了派生一個具體類去實現(xiàn)修改屹篓。

里氏替換原則

里氏替換原則是一個非常有用的一個概念疙渣。他的定義

如果對每一個類型為T1的對象o1,都有類型為T2的對象o2,使得以T1定義的所有程序P在所有對象o1都替換成o2的時候,程序P的行為都沒有發(fā)生變化堆巧,那么類型T2是類型T1的子類型妄荔。

這樣說有點復雜泼菌,其實有一個簡單的定義

所有引用基類的地方必須能夠透明地使用其子類的對象。

里氏替換原則通俗的去講就是:子類可以去擴展父類的功能啦租,但是不能改變父類原有的功能哗伯。他包含以下幾層意思:

  1. 子類可以實現(xiàn)父類的抽象方法,但是不能覆蓋父類的非抽象方法篷角。
  2. 子類可以增加自己獨有的方法焊刹。
  3. 當子類的方法重載父類的方法時候,方法的形參要比父類的方法的輸入?yún)?shù)更加寬松恳蹲。
  4. 當子類的方法實現(xiàn)父類的抽象方法時虐块,方法的返回值要比父類更嚴格。

里氏替換原則之所以這樣要求是因為繼承有很多缺點嘉蕾,他雖然是復用代碼的一種方法非凌,但同時繼承在一定程度上違反了封裝。父類的屬性和方法對子類都是透明的荆针,子類可以隨意修改父類的成員敞嗡。這也導致了,如果需求變更航背,子類對父類的方法進行一些復寫的時候喉悴,其他的子類無法正常工作。所以里氏替換法則被提出來玖媚。
確保程序遵循里氏替換原則可以要求我們的程序建立抽象箕肃,通過抽象去建立規(guī)范,然后用實現(xiàn)去擴展細節(jié)今魔,這個是不是很耳熟勺像,對,里氏替換原則和開閉原則往往是相互依存的错森。

依賴倒置原則

依賴倒置原則指的是一種特殊的解耦方式吟宦,使得高層次的模塊不應(yīng)該依賴于低層次的模塊的實現(xiàn)細節(jié)的目的旺矾,依賴模塊被顛倒了扛邑。
這也是一個讓人難懂的定義,他可以簡單來說就是

高層模塊不應(yīng)該依賴底層模塊导街,兩者都應(yīng)該依賴其抽象
抽象不應(yīng)該依賴細節(jié)
細節(jié)應(yīng)該依賴抽象

在Java 中抽象指的是接口或者抽象類瓦阐,兩者皆不能實例化蜗侈。而細節(jié)就是實現(xiàn)類,也就是實現(xiàn)了接口或者繼承了抽象類的類睡蟋。他是可以被實例化的踏幻。高層模塊指的是調(diào)用端,底層模塊是具體的實現(xiàn)類戳杀。在Java中该面,依賴倒置原則是指模塊間的依賴是通過抽象來發(fā)生的夭苗,實現(xiàn)類之間不發(fā)生直接的依賴關(guān)系,其依賴關(guān)系是通過接口是來實現(xiàn)的吆倦。這就是俗稱的面向接口編程。
我們下面有一個例子來講述這個問題坐求。這個例子是工人用錘子來修理東西蚕泽。我們的代碼如下:

public class Hammer {
    public String function(){
        return "用錘子修理東西";
    }
}

public class Worker {
    public void fix(Hammer hammer){
        System.out.println("工人" + hammer.function());
    }


    public static void main(String[] args) {
        new Worker().fix(new Hammer());
    }
}

這個是一個很簡單的例子,但是如果我們要新增加一個功能桥嗤,工人用 螺絲刀來修理東西须妻,在這個類,我們發(fā)現(xiàn)是很難做的泛领。因為我們Worker類依賴于一個具體的實現(xiàn)類Hammer荒吏。所以我們用到面向接口編程的思想,改成如下的代碼:

public interface Tools {
    public String function();
}

然后我們的Worker是通過這個接口來于其他細節(jié)類進行依賴渊鞋。代碼如下:

public class Worker {
    public void fix(Tools tool){
        System.out.println("工人" + tool.function());
    }


    public static void main(String[] args) {
        new Worker().fix(new Hammer());
        new Worker().fix(new Screwdriver());

    }
}

我們的Hammer類與Screwdriver類實現(xiàn)這個接口

public class Hammer implements Tools{
    public String function(){
        return "用錘子修理東西";
    }
}

public class Screwdriver implements Tools{
    @Override
    public String function() {
        return "用螺絲刀修理東西";
    }
}

這樣绰更,通過面向接口編程,我們的代碼就有了很高的擴展性锡宋,降低了代碼之間的耦合度儡湾,提高了系統(tǒng)的穩(wěn)定性。

接口隔離原則

接口隔離原則的定義是

客戶端不應(yīng)該依賴他不需要的接口

換一種說法就是類間的依賴關(guān)系應(yīng)該建立在最小的接口上执俩。這樣說好像更難懂徐钠。我們通過一個例子來說明。

我們知道在Java中一個具體類實現(xiàn)了一個接口役首,那必然就要實現(xiàn)接口中的所有方法尝丐。如果我們有一個類A和類B通過接口I來依賴,類B是對類A依賴的實現(xiàn)衡奥,這個接口I有5個方法爹袁。但是類A與類B只通過方法1,2,3依賴,然后類C與類D通過接口I來依賴矮固,類D是對類C依賴的實現(xiàn)但是他們卻是通過方法1,4,5依賴呢簸。那么是必在實現(xiàn)接口的時候,類B就要有實現(xiàn)他不需要的方法4和方法5 而類D就要實現(xiàn)他不需要的方法2乏屯,和方法3根时。這簡直就是一個災(zāi)難的設(shè)計。
所以我們需要對接口進行拆分辰晕,就是把接口分成滿足依賴關(guān)系的最小接口蛤迎,類B與類D不需要去實現(xiàn)與他們無關(guān)接口方法。比如在這個例子中含友,我們可以把接口拆成3個替裆,第一個是僅僅由方法1的接口校辩,第二個接口是包含2,3方法的,第三個接口是包含4,5方法的辆童。
這樣宜咒,我們的設(shè)計就滿足了接口隔離原則。

以上這些設(shè)計思想用英文的第一個字母可以組成SOLID 把鉴,滿足這個5個原則的程序也被稱為滿足了SOLID準則故黑。

迪米特原則

迪米特原則也被稱為最小知識原則,他的定義

一個對象應(yīng)該對其他對象保持最小的了解庭砍。

因為類與類之間的關(guān)系越密切场晶,耦合度越大,當一個類發(fā)生改變時怠缸,對另一個類的影響也越大诗轻,所以這也是我們提倡的軟件編程的總的原則:低耦合,高內(nèi)聚揭北。
迪米特法則還有一個更簡單的定義

只與直接的朋友通信扳炬。首先來解釋一下什么是直接的朋友:每個對象都會與其他對象有耦合關(guān)系,只要兩個對象之間有耦合關(guān)系搔体,我們就說這兩個對象之間是朋友關(guān)系鞠柄。耦合的方式很多,依賴嫉柴、關(guān)聯(lián)厌杜、組合、聚合等计螺。其中夯尽,我們稱出現(xiàn)成員變量、方法參數(shù)登馒、方法返回值中的類為直接的朋友匙握,而出現(xiàn)在局部變量中的類則不是直接的朋友。也就是說陈轿,陌生的類最好不要作為局部變量的形式出現(xiàn)在類的內(nèi)部圈纺。

這里我們可以用一個現(xiàn)實生活中的例子來講解一下。比如我們需要一張CD,我們可能去音像店去問老板有沒有我們需要的那張CD麦射,老板說現(xiàn)在沒有蛾娶,等有的時候你們來拿就行了。在這里我們不需要關(guān)心老板是從哪里潜秋,怎么獲得的那張CD蛔琅,我們只和老板(直接朋友)溝通,至于老板從他的朋友那里通過何種條件得到的CD峻呛,我們不關(guān)心罗售,我們不和老板的朋友(陌生人)進行通信辜窑,這個就是迪米特的一個應(yīng)用。說白了寨躁,就是一種中介的方式穆碎。我們通過老板這個中介來和真正提供CD的人發(fā)生聯(lián)系。

總結(jié)

到這里职恳,面向?qū)ο蟮牧笤瓌t所禀,就寫完了。我們看出來话肖,這些原則其實都是應(yīng)對不斷改變的需求北秽。每當需求變化的時候葡幸,我們利用這些原則來使我們的代碼改動量最小最筒,而且所造成的影響也是最小的。但是我們在看這些原則的時候蔚叨,我們會發(fā)現(xiàn)很多原則并沒有提供一種公式化的結(jié)論床蜘,而即使提供了公式化的結(jié)論的原則也只是建議去這樣做。這是因為蔑水,這些設(shè)計原則本來就是從很多實際的代碼中提取出來的邢锯,他是一個經(jīng)驗化的結(jié)論。怎么去用它搀别,用好他丹擎,就要依靠設(shè)計者的經(jīng)驗。否則一味者去使用設(shè)計原則可能會使代碼出現(xiàn)過度設(shè)計的情況歇父。大多數(shù)的原則都是通過提取出抽象和接口來實現(xiàn)蒂培,如果發(fā)生過度的設(shè)計,就會出現(xiàn)很多抽象類和接口榜苫,增加了系統(tǒng)的復雜度护戳。讓本來很小的項目變得很龐大,當然這也是Java的特性(任何的小項目都會做成中型的項目)垂睬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末媳荒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子驹饺,更是在濱河造成了極大的恐慌钳枕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赏壹,死亡現(xiàn)場離奇詭異么伯,居然都是意外死亡,警方通過查閱死者的電腦和手機卡儒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門田柔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俐巴,“玉大人,你說我怎么就攤上這事硬爆⌒蓝妫” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵缀磕,是天一觀的道長缘圈。 經(jīng)常有香客問我,道長袜蚕,這世上最難降的妖魔是什么糟把? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮牲剃,結(jié)果婚禮上遣疯,老公的妹妹穿的比我還像新娘。我一直安慰自己凿傅,他們只是感情好缠犀,可當我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著聪舒,像睡著了一般辨液。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上箱残,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天滔迈,我揣著相機與錄音,去河邊找鬼被辑。 笑死燎悍,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的敷待。 我是一名探鬼主播间涵,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼榜揖!你這毒婦竟也來了勾哩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤举哟,失蹤者是張志新(化名)和其女友劉穎思劳,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妨猩,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡潜叛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片威兜。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡销斟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出椒舵,到底是詐尸還是另有隱情蚂踊,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布笔宿,位于F島的核電站犁钟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏泼橘。R本人自食惡果不足惜涝动,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望炬灭。 院中可真熱鬧醋粟,春花似錦、人聲如沸担败。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽提前。三九已至,卻和暖如春泳唠,著一層夾襖步出監(jiān)牢的瞬間狈网,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工笨腥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拓哺,地道東北人。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓脖母,卻偏偏與公主長得像士鸥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谆级,可洞房花燭夜當晚...
    茶點故事閱讀 44,665評論 2 354