聊聊軟件設(shè)計(jì)原則

軟件設(shè)計(jì)知識(shí)是一名軟件開發(fā)人員必須要懂的知識(shí),最近幾天今天看了bob大叔的《敏捷軟件開發(fā)》一書和軟件設(shè)計(jì)相關(guān)的一些blog和資料并炮,自己做了一個(gè)學(xué)習(xí)筆記

設(shè)計(jì)目標(biāo)

正確性呵哨、健壯性、靈活性、可重用性屿愚、高效性

降低復(fù)雜性

  • 所謂復(fù)雜性,就是任何使得軟件難于理解和修改的因素务荆。
  • 復(fù)雜性的來(lái)源主要有兩個(gè):代碼的含義模糊和互相依賴

    • 模糊指的是妆距,代碼里的重要信息看不出來(lái);
    • 依賴指的是函匕,某個(gè)模塊的代碼娱据,不結(jié)合其他模塊的代碼,就無(wú)法理解
  • 危害:復(fù)雜性的危害在于盅惜,它會(huì)遞增中剩。如果做錯(cuò)了一個(gè)決定,導(dǎo)致后面的代碼都基于前面的錯(cuò)誤實(shí)現(xiàn)抒寂,只會(huì)越來(lái)越復(fù)雜结啼。"常聽人說(shuō),我們先把產(chǎn)品做出來(lái)屈芜,后面再改進(jìn)"郊愧,這很難做到

  • ==關(guān)鍵==:找出易變化的部分井佑,合理抽象属铁。
    用抽象構(gòu)建框架、用實(shí)現(xiàn)擴(kuò)展細(xì)節(jié)

代碼抽象三原則:

1. Don’t Repeat Yourself (DRY)

  • 系統(tǒng)的每一個(gè)功能都應(yīng)該有唯一的實(shí)現(xiàn)躬翁。也就是說(shuō)焦蘑,如果多次遇到同樣的問(wèn)題,就應(yīng)該抽象出一個(gè)共同的解決方法盒发,不要重復(fù)開發(fā)同樣的功能
    不要重復(fù)自己

2. You Ain’t Gonna Need It (YAGNI)

  • 定義:你不會(huì)需要它喇肋,只考慮和設(shè)計(jì)必須的功能坟乾,避免過(guò)度設(shè)計(jì)
  • 這是"極限編程"提倡的原則,指的是你自以為有用的功能蝶防,實(shí)際上都是用不到的甚侣。因此,除了最核心的功能间学,其他功能一概不要部署殷费,這樣可以大大加快開發(fā)
  • 你會(huì)發(fā)現(xiàn)DRY原則和YAGNI原則并非完全兼容。前者追求"抽象化"低葫,要求找到通用的解決方法详羡;后者追求"快和省"

3.Rule Of Three

  • 稱為"三次原則",指的是當(dāng)某個(gè)功能第三次出現(xiàn)時(shí)嘿悬,才進(jìn)行"抽象化"实柠。

  • 這樣做有幾個(gè)理由:

    • 省事。如果一種功能只有一到兩個(gè)地方會(huì)用到善涨,就不需要在"抽象化"上面耗費(fèi)時(shí)間了窒盐。

    • 容易發(fā)現(xiàn)模式。"抽象化"需要找到問(wèn)題的模式钢拧,問(wèn)題出現(xiàn)的場(chǎng)合越多蟹漓,就越容易看出模式,從而可以更準(zhǔn)確地"抽象化"源内。

    • 防止過(guò)度冗余葡粒。如果一種功能同時(shí)有多個(gè)實(shí)現(xiàn),管理起來(lái)非常麻煩膜钓,修改的時(shí)候需要修改多處嗽交。在實(shí)際工作中,重復(fù)實(shí)現(xiàn)最多可以容忍出現(xiàn)一次颂斜,再多就無(wú)法接受了夫壁。

  • 小結(jié):綜上所述,"三次原則"是DRY原則和YAGNI原則的折衷焚鲜,是代碼冗余和開發(fā)成本的平衡點(diǎn)掌唾,值得我們?cè)?抽象化"時(shí)遵循

面向?qū)ο蟮腟.O.L.I.D原則

1. SRP職責(zé)單一原則

  • 核心思想是一個(gè)類只做一件事,把事情做好忿磅,其只有一個(gè)引起它變化的原因糯彬,職責(zé)過(guò)多,引起它變化的原因就越多葱她,將導(dǎo)致責(zé)任依賴增加耦合性
  • 遵循單一職責(zé)原的優(yōu)點(diǎn)有:
    • 可以降低類的復(fù)雜度撩扒,一個(gè)類只負(fù)責(zé)一項(xiàng)職責(zé),其邏輯肯定要比負(fù)責(zé)多項(xiàng)職責(zé)簡(jiǎn)單的多;
    • 提高類的可讀性搓谆,提高系統(tǒng)的可維護(hù)性炒辉;
    • 變更引起的風(fēng)險(xiǎn)降低,變更是必然的泉手,如果單一職責(zé)原則遵守的好黔寇,當(dāng)修改一個(gè)功能時(shí),可以顯著降低對(duì)其他功能的影響斩萌。
  • 應(yīng)用場(chǎng)景:迭代器

2. 里氏替換原則

  • 定義:所有引用基類的地方必須能透明地使用其子類的對(duì)象缝裤,替換之后,代碼還能正常工作颊郎。它是使代碼符合開閉原則的重要保證.
  • 問(wèn)題:有一功能P1憋飞,由類A完成。現(xiàn)需要將功能P1進(jìn)行擴(kuò)展姆吭,擴(kuò)展后的功能為P榛做,其中P由原有功能P1與新功能P2組成。新功能P由類A的子類B來(lái)完成内狸,則子類B在完成新功能P2的同時(shí)检眯,有可能會(huì)導(dǎo)致原有功能P1發(fā)生故障
  • 解決:當(dāng)使用繼承時(shí),遵循里氏替換原則答倡。類B繼承類A時(shí)轰传,除添加新的方法完成新增功能P2外驴党,盡量不要重寫父類A的方法瘪撇,也盡量不要重載父類A的方法
  • 換個(gè)說(shuō)法是,子類可以擴(kuò)展父類的功能港庄,但不能改變父類原有的功能(不能破壞繼承體系)
    1. 子類可以實(shí)現(xiàn)父類的抽象方法倔既,但不能覆蓋父類的非抽象方法
    2. 子類中可以增加自己特有的方法
    3. 當(dāng)子類的方法重載父類的方法時(shí),方法的前置條件(即方法的形參)要比父類方法的輸入?yún)?shù)更寬松鹏氧。
    4. 當(dāng)子類的方法實(shí)現(xiàn)父類的抽象方法時(shí)渤涌,方法的后置條件(即方法的返回值)要比父類更嚴(yán)格

3. 接口隔離原則

  • 定義:客戶端不應(yīng)該依賴它不需要的接口;一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小的接口上把还。
  • 規(guī)約:建立單一接口实蓬,不要建立龐大臃腫的接口,盡量細(xì)化接口吊履,接口中的方法盡量少安皱,但不要過(guò)度。也就是說(shuō)艇炎,我們要為各個(gè)類建立專用的接口酌伊,而不要試圖去建立一個(gè)很龐大的接口供所有依賴它的類去調(diào)用。接口是設(shè)計(jì)時(shí)對(duì)外部設(shè)定的“契約”缀踪,通過(guò)分散定義多個(gè)接口居砖,可以預(yù)防外來(lái)變更的擴(kuò)散虹脯,提高系統(tǒng)的靈活性和可維護(hù)性。
  • 示例:人們對(duì)電腦有不同的使用方式:如上網(wǎng)奏候、看電影循集、寫文檔、玩游戲蔗草、通訊暇榴、計(jì)算和存儲(chǔ)等.如果都把這些功能都定義在電腦的抽象類里面。那各種功能類型的電腦(如上網(wǎng)本蕉世、服務(wù)器蔼紧、PC、智能學(xué)習(xí)機(jī))都要現(xiàn)實(shí)這些接口狠轻。所以奸例,應(yīng)該把這些接口隔離開,這樣不同功能的電腦只需要實(shí)現(xiàn)自己需要的接口.
接口隔離2.jpg
接口隔離1.jpg

4. 依賴倒置原則

  • 定義:高層模塊不應(yīng)該依賴底層模塊的實(shí)現(xiàn)向楼,而是依賴高層抽象查吊。而且,二者都應(yīng)該依賴于抽象湖蜕。抽象不應(yīng)該依賴細(xì)節(jié)逻卖;細(xì)節(jié)應(yīng)該依賴抽象
  • 問(wèn)題:類A直接依賴類B,假如要將類A改為依賴類C昭抒,則必須通過(guò)修改類A的代碼來(lái)達(dá)成评也。這種場(chǎng)景下,類A一般是高層模塊灭返,負(fù)責(zé)復(fù)雜的業(yè)務(wù)邏輯盗迟;類B和類C是低層模塊,負(fù)責(zé)基本的原子操作熙含;假如修改類A罚缕,會(huì)給程序帶來(lái)不必要的風(fēng)險(xiǎn)
  • 解決:將類A修改為依賴接口I,類B和類C各自實(shí)現(xiàn)接口I怎静,類A通過(guò)接口I間接與類B或者類C發(fā)生聯(lián)系邮弹,則會(huì)大大降低修改類A的幾率
  • 核心思想:面向接口編程,在java中蚓聘,抽象指的是接口或者抽象類腌乡,細(xì)節(jié)就是具體的實(shí)現(xiàn)類,使用接口或者抽象類的目的是制定好規(guī)范和契約或粮,而不去涉及任何具體的操作导饲,把展現(xiàn)細(xì)節(jié)的任務(wù)交給他們的實(shí)現(xiàn)類去完成。
  • 好處:可以降低類之間的耦合性,提高系統(tǒng)的穩(wěn)定性渣锦,降低修改程序造成的風(fēng)險(xiǎn)硝岗。
  • 應(yīng)用模式:工廠模式
  • 規(guī)范:實(shí)際編程中,最好做到如下3點(diǎn):
    1. 低層模塊盡量都要有抽象類或接口袋毙,或者兩者都有型檀。
    2. 變量的聲明類型盡量是抽象類或接口。
    3. 使用繼承時(shí)遵循里氏替換原則

如果依賴的是一個(gè)穩(wěn)定的具體類听盖,那么可以直接依賴它

  • 層次化
    • 方式1:高層模塊依賴底層實(shí)現(xiàn)模塊胀溺,這種依賴性是傳遞的


      依賴倒置1.png
  • 方式2
    - 解除傳遞依賴關(guān)系
    - 接口所有權(quán)倒置:客戶擁有抽象接口,它的服務(wù)者從這些抽象接口中派生皆看,底層模塊實(shí)現(xiàn)了在高層模塊聲明并被高層模塊調(diào)用的接口


    依賴倒置2.png

5. 開放/封閉原則

  • 對(duì)擴(kuò)展開放仓坞,對(duì)修改關(guān)閉。如果有新的需求和變化可以對(duì)現(xiàn)有代碼進(jìn)行擴(kuò)展腰吟,以適應(yīng)新的情況.而不是對(duì)原有代碼進(jìn)行修改.
  • 解決:關(guān)鍵在于抽象无埃、預(yù)測(cè)和刺激變化
  • 應(yīng)用模式:裝飾者模式(如java.io包),不改變?cè)写a擴(kuò)展對(duì)象的行為

其他原則

1. Keep it sample,stupid(Kiss)

  • 保持簡(jiǎn)單毛雇、直接嫉称,不要復(fù)雜化
  • 模塊分成接口和實(shí)現(xiàn)。接口要簡(jiǎn)單灵疮,實(shí)現(xiàn)可以復(fù)雜织阅。
  • 好的 class 應(yīng)該是"小接口,大功能",大量的功能隱藏在簡(jiǎn)單接口之下震捣,對(duì)用戶不可見荔棉,用戶感覺(jué)不到這是一個(gè)復(fù)雜的 class.比如Unix 的文件讀寫接口

2. Program to an interface, not an implementation

  • 面向接口編程,而不是實(shí)現(xiàn)
  • 工廠模式伍派、策略模式等等

3. 高內(nèi)聚低耦合

  • 將模塊間的耦合降到最低江耀,努力讓一個(gè)模塊做到精益求精.內(nèi)聚意味著獨(dú)立和重用剩胁,耦合意味著多米諾骨牌效應(yīng).

4. 迪米特法則

又稱最少知識(shí)原則诉植,該原則告訴我們要降低耦合。

  • 定義:一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象保持最少的了解

  • 問(wèn)題:類與類之間的關(guān)系越密切昵观,耦合度越大晾腔,當(dāng)一個(gè)類發(fā)生改變時(shí),對(duì)另一個(gè)類的影響也越大啊犬。

  • 解決:盡量降低類與類之間的耦合

  • 對(duì)于對(duì)象 ‘O’ 中一個(gè)方法’M’灼擂,M 應(yīng)該只能夠訪問(wèn)以下對(duì)象中的方法:

    • 對(duì)象O本身
    • 參數(shù)對(duì)象
    • 與對(duì)象O直接相關(guān)的對(duì)象
    • 方法中創(chuàng)建或?qū)嵗膶?duì)象
  • 應(yīng)用模式:外觀模式,提供一個(gè)統(tǒng)一的接口來(lái)訪問(wèn)子系統(tǒng)中的一群接口觉至。外觀定義了一個(gè)高層接口剔应,讓系統(tǒng)更容易使用

5. 好萊塢原則

  • 你不要找我,我會(huì)找你 。 高層組件對(duì)待底層組件的方式:別調(diào)用我們峻贮,我們會(huì)調(diào)用你
  • 應(yīng)用場(chǎng)景:
    • 觀察者模式,以通知替代輪詢
    • 工廠模式
    • Ioc依賴注入,DI控制反轉(zhuǎn)設(shè)計(jì)的基礎(chǔ)席怪,所有組件都是被動(dòng)的,初始化和調(diào)用都由容器負(fù)責(zé)
    • 模板模式

6. 無(wú)環(huán)依賴原則

  • 包纤控、服務(wù)之間的依賴結(jié)構(gòu)必須是一個(gè)直接的無(wú)環(huán)圖形挂捻,不能出現(xiàn)循環(huán)依賴
  • 打破循環(huán)依賴關(guān)系,解決關(guān)系耦合問(wèn)題:
    • 使用依賴倒置原則和接口隔離原則
    • 創(chuàng)建新的包船万,將共同類抽象出來(lái)放在新的包里

7. 減少拋異常

  • 除了那些必須告訴用戶的錯(cuò)誤刻撒,其他錯(cuò)誤盡量在軟件內(nèi)部處理掉,不要拋出

總結(jié)

  • 如何去遵守這些原則耿导。對(duì)這些原則的遵守并不是是和否的問(wèn)題声怔,而是多和少的問(wèn)題,也就是說(shuō)舱呻,我們一般不會(huì)說(shuō)有沒(méi)有遵守捧搞,而是說(shuō)遵守程度的多少。任何事都是過(guò)猶不及狮荔,設(shè)計(jì)模式的六個(gè)設(shè)計(jì)原則也是一樣胎撇,制定這六個(gè)原則的目的并不是要我們刻板的遵守他們,而需要根據(jù)實(shí)際情況靈活運(yùn)用殖氏。對(duì)他們的遵守程度只要在一個(gè)合理的范圍內(nèi)晚树,就算是良好的設(shè)計(jì)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雅采,一起剝皮案震驚了整個(gè)濱河市爵憎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌婚瓜,老刑警劉巖宝鼓,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異巴刻,居然都是意外死亡愚铡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門胡陪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)沥寥,“玉大人,你說(shuō)我怎么就攤上這事柠座∫匮牛” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵妈经,是天一觀的道長(zhǎng)淮野。 經(jīng)常有香客問(wèn)我捧书,道長(zhǎng),這世上最難降的妖魔是什么骤星? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任鳄厌,我火速辦了婚禮,結(jié)果婚禮上妈踊,老公的妹妹穿的比我還像新娘了嚎。我一直安慰自己,他們只是感情好廊营,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布歪泳。 她就那樣靜靜地躺著,像睡著了一般露筒。 火紅的嫁衣襯著肌膚如雪呐伞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天慎式,我揣著相機(jī)與錄音伶氢,去河邊找鬼。 笑死瘪吏,一個(gè)胖子當(dāng)著我的面吹牛癣防,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掌眠,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼蕾盯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蓝丙?” 一聲冷哼從身側(cè)響起级遭,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渺尘,沒(méi)想到半個(gè)月后挫鸽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸥跟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年丢郊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锌雀。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚂夕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出腋逆,到底是詐尸還是另有隱情,我是刑警寧澤侈贷,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布惩歉,位于F島的核電站等脂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏撑蚌。R本人自食惡果不足惜上遥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望争涌。 院中可真熱鬧粉楚,春花似錦、人聲如沸亮垫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)饮潦。三九已至燃异,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間继蜡,已是汗流浹背回俐。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稀并,地道東北人仅颇。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像碘举,于是被迫代替她去往敵國(guó)和親灵莲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

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

  • 設(shè)計(jì)模式概述 在學(xué)習(xí)面向?qū)ο笃叽笤O(shè)計(jì)原則時(shí)需要注意以下幾點(diǎn):a) 高內(nèi)聚殴俱、低耦合和單一職能的“沖突”實(shí)際上政冻,這兩者...
    彥幀閱讀 3,752評(píng)論 0 14
  • 目錄: 設(shè)計(jì)模式六大原則(1):?jiǎn)我宦氊?zé)原則 設(shè)計(jì)模式六大原則(2):里氏替換原則 設(shè)計(jì)模式六大原則(3):依賴倒...
    加油小杜閱讀 729評(píng)論 0 1
  • 轉(zhuǎn)載自 設(shè)計(jì)模式六大原則[http://www.uml.org.cn/sjms/201211023.asp#3] ...
    廚子閱讀 1,100評(píng)論 2 5
  • 堅(jiān)持分享第400天( 原創(chuàng)總第568天 2018年6月26日 星期二) 小嘟嘟到我家的第一天洗了澡,第二天就...
    紅云_楊柳清風(fēng)閱讀 528評(píng)論 0 0
  • 【原創(chuàng)詩(shī)歌】 只因?yàn)槟晟俚妮p狂 才渴望去流浪遠(yuǎn)方 似乎可以再無(wú)牽念 也不必在乎誰(shuí)的微笑 讓夕陽(yáng)的斜暉 模糊離情別緒...
    淡淡青蓮閱讀 373評(píng)論 30 21