面向對象的7個設計原則->開車理解->貼近生活

  設計模式在我們的開發中是不可或缺的一部分,很多人會說,我沒用那些設計模式啊,我也開發的挺好的,其實不然,我們在開發中都用到了這些設計模式,只不過我們並沒有在意這些,今天我就用開車的方法來解釋一下我們的7個設計原則。

簡述

  面向對象的設計原則有七個,包括:開閉原則、單一職責原則、里氏替換原則、迪米特原則(最少知道原則)、接口分離原則、依賴倒置原則、組合/聚合複用原則。

1>開閉原則:

  在面向對象編程領域中,開閉原則規定“軟件中的對象(類,模塊,函數等等)應該對於擴展是開放的,但是對於修改是封閉的”,這意味着一個實體是允許在不改變它的源代碼的前提下變更它的行爲。該特性在產品化的環境中是特別有價值的,在這種環境中,改變源代碼需要代碼審查,單元測試以及諸如此類的用以確保產品使用質量的過程。遵循這種原則的代碼在擴展時並不發生改變,因此無需上述的過程。摘自某度百科。

  上述那段話我是沒看懂什麼意思(我也沒仔細的去看),開閉原則一句話來解釋就是對擴展開放,對修改關閉。

  我們來舉幾個生活的栗子,小張開了一個飯店,湘菜做的很棒,顧客也越來越多了,也出現了在吃飯時間排隊等候的現象,小張這時意識到我們應該擴張一下我們的飯店的規模了,於是把相鄰的門店也一併租了下來,有人建議小張,你既然擴張了飯店的規模建議你去做一些別的事(嚴重不符合開閉原則),但是小張堅持還是做湘菜(符合開閉原則),也就是說小張你是在於原有的基礎之上做了規模的擴張,而沒有改變飯店原有特色菜的本質,這就是一個開閉原則的栗子。

  再比如,小張去洗浴中心or足療保健or洗頭房,我們可以點一些***的服務,我們也可以提出一些別的要求,比如花式開心,不管你提什麼要求,也離不開,你想做的那些事的本質,不可能有人要求洗頭小妹給你修腳吧。。。這裏就是我們的可以提出對於***服務的擴展花樣,但是不會修改原有***服務的本質。這也就是我們的開閉原則。

  從代碼角度來說,就是無論我們如何去擴展類的方法和屬性,也不要修改類本質的方法和屬性,只擴展不修改現有,也禁止修改原有的屬性。開閉原則是下面那些原則的總綱,切記很重要。


 2>單一職責原則:

  單一職責原則(SRP:Single responsibility principle)又稱單一功能原則,面向對象五個基本原則(SOLID)之一。它規定一個類應該只有一個發生變化的原因。該原則由羅伯特·C·馬丁(Robert C. Martin)於《敏捷軟件開發:原則、模式和實踐》一書中給出的。馬丁表示此原則是基於湯姆·狄馬克(Tom DeMarco)和Meilir Page-Jones的著作中的內聚性原則發展出的。摘自某度百科。

  單一職責,這個應該很好理解的,只做一件事,做好一件事就夠了,生活中我們也常常會說,做好一件事不難,難的是一輩子只做這一件事。職責原則一句話來解釋就是請做好自己的事。

  在生活中栗子有很多的,還是我們的小張開飯店的栗子,上面說了小張的飯店開的很紅火,生意很好,之所以生意會好,是他一直堅持做他的特色菜,很多年了味道一直沒有變過,還是那種熟悉的家鄉味,有人建議他把特色菜的技術融入到燒烤,烤肉上去,小張搖搖頭說,我們這是湘菜館,不是烤肉店,我能一直做好我現在的特色菜就夠了。這就是我們職責單一原則,兩耳不聞別的事,單一隻做一件事。

  再比如,小張又來足療保健了,不耽誤時間了,直接上樓吧,“來啊,服務員,來盤魚香肉絲”。😂說完這句話,我怕老闆娘會打死你。也就是說我們的職責是單一,來足療店了,一樓洗腳的,二樓,***服務的。你來我這點魚香肉絲...明顯這很不符合常理啊。

  我們代碼也應該是如此的,我們建立了一個Member類,主要是用來增刪改查會員信息的,你現在寫了一個積分新增的方法,你覺得合適嗎?爲了我們的代碼的整潔,爲了我們下次能找到積分新增的方法,你別把積分新增寫Member類裏好嗎?😂我清晰的記得我們一個類幹完一個項目的事....

 


 3>里氏替換原則:

   里氏替換原則,OCP作爲OO的高層原則,主張使用“抽象(Abstraction)”和“多態(Polymorphism)”將設計中的靜態結構改爲動態結構,維持設計的封閉性。“抽象”是語言提供的功能。“多態”由繼承語義實現。摘自某度百科。

   就是我們在繼承的時候,子類的實現不要更改父類的方法,我們可以重寫但是別改原來的方法。一句話說,你愛的事別人不一定愛。

   快要到中午吃飯的時間了,小張的飯店陸陸續續來了很多客人,有一桌客人點菜過程中發生了這樣一件事,“喲,湘菜館,我們點一個湘西外婆菜吧,好久沒吃了”,“算了吧,我們上次去的那個小趙湘菜館,沒有湘西外婆菜,他這...也應該沒有”,說到這我們可以看到這個人的思想是錯誤的,說到代碼裏就是,湘菜館是一個父類,小趙湘菜館和小張湘菜館是子類,不能因爲小趙湘菜館沒有湘西外婆菜,你就把所有的湘菜館(父類)至爲沒有湘西外婆菜吧。

  忙完了中午,小張的腰包也變得鼓鼓的了,走起,足療,上樓,關門..."服務員,來個可以沙漠風暴的。",“對不起先生,我們這沒有沙漠風暴”,“算了,我換一家店吧”。到了第二家店,上樓,關門,“服務員,你家沒有沙漠風暴吧~!”,“先生,我家各個可以沙漠風暴,不能因爲一家店沒有,你就說所有店都沒有啊,您說是吧”。

  到我們實際代碼上,比如我們建立了一個鳥類,屬性是有羽毛,會飛等等,但是企鵝繼承了我們的類,企鵝並不會飛,但我們並不能修改掉去說,所有的鳥類都不能飛,畢竟會飛鳥類還是大多數。

 4>迪米特原則:

  迪米特法則(Law of Demeter)又叫作最少知識原則(Least Knowledge Principle 簡寫LKP),就是說一個對象應當對其他對象有儘可能少的瞭解,不和陌生人說話。英文簡寫爲: LoD。摘自某度百科。

  感覺這個某度百科寫的很容易理解,也就是我們的告訴你的,你知道,不告訴你的,你也別去問,一句話來說就是,知道太多對你沒好處。

  小張的飯店今天來了一大桌子的客人,據說是縣裏的老闆宴請客戶吃飯,“服務員點菜,來個剁椒魚頭....”,“好的,馬上給您下單,請問您叫什麼名字,您家住在哪裏?家裏幾口人”...你有病吧,我就來吃個飯,你至於問我那麼多事情嗎?我們可想而知,可能服務員快要捱打了,也很不符合常理的,我們只需要知道客人要吃什麼就可以了,別的不需要知道,也沒有必要知道。

  小張的身體素質還是很不錯的,被打以後,沒到三天就出院了,回家的路上,唉~!巧了路過一個足療店,走起。上樓,關門,start...."小麗,技術還算不錯的嘛?幹幾年了?這玩意賺錢嗎?家裏家口人啊?有男朋友嗎?男朋友hi做什麼的啊?",很明顯,在足療店出來轉身又回醫院了。

   

  從代碼的角度來說,我們只寫好我們當前的方法就可以了,別管其他方法內有什麼參數,其他方法都做了什麼。管好自己在說...


5>依賴倒置原則:

  依賴倒置原則(Dependence Inversion Principle)是程序要依賴於抽象接口,不要依賴於具體實現。簡單的說就是要求對抽象進行編程,不要對實現進行編程,這樣就降低了客戶與實現模塊間的耦合。摘自某度百科。

  依賴倒置原則就是面向我們的接口編程,接口有什麼,我們去做什麼,而不是我們做了什麼,再去加什麼樣的接口,一句話來說,根據接口寫代碼。

  比如小張的飯店,早起需要買菜供給今天一整天的菜品原材料,我們可以把菜品原材料比作接口,把做好的菜比作實現類,也就是說,我們每天買了什麼菜品原材料,然後去做什麼樣的菜品,而不是因爲你要做什麼菜品,而去現買菜品的原材料的。

  小張忙裏偷閒,又來到了足療店,但是他忘記了他今天其實是想要去髮廊的,理髮等等事情要在髮廊完成,進足療店,上樓,“服務員,給我洗洗頭...”顯得好尷尬...足療店,你要洗頭...足療店不可能根據你的需求,臨時去加洗頭的業務,也就是我們的小張,應該按照他去的足療店的規矩來洗腳,而不是小張隨心所欲的想要洗頭就洗頭。

  代碼也是如此,我們都是先寫好每一個接口,考慮好我們大概需要什麼樣的業務,然後去編寫實現類。 


 6>接口分離原則:

  接口分離原則指在設計時採用多個與特定客戶類有關的接口比採用一個通用的接口要好。即,一個類要給多個客戶使用,那麼可以爲每個客戶創建一個接口,然後這個類實現所有的接口;而不要只創建一個接口,其中包含所有客戶類需要的方法,然後這個類實現這個接口。摘自某度百科。

  接口分離也很好理解的,和我們的職責單一其實差不多的,就是可以將一個總體的接口,按照一定的類別進行劃分,換成一句話來說,就是一個小接口只做一類事情。

  小張的飯店依舊紅火,他發現,後廚切菜的人員不夠用了,現在他們招聘一個切墩的。於是去人才市場看一看,找到了一些合適的人員,有一個團隊說,我們是系統化的,從洗菜,切菜,到炒菜,到洗碗,我們可以一條龍來完成的,你要一個切菜的人員,建議把我們全都僱傭過去,小張並不想這樣,因爲畢竟只是少了一個切菜的,不是全系統的後廚啊。團隊看到他這番反應,趕緊又說,我們也可以只提供洗菜切菜服務的,您看滿意嗎?這也恰恰就是我們想要的,也就是有時候並不是全面纔是更好的,我們應該儘可能將菜品處理,菜品的製作,器皿的清洗分開來進行組成團隊。

  這次後廚可以忙的開了,小張下午沒事又來到了足療店,由於不是休息日,店裏的顧客並不是很多,很多小妹都閒着,不多說,先上樓,來了服務員介紹,這個是小花,這個是大美,他們是一個姐妹組合,但小張完成無法接受姐妹花組合,只好點了小花一個人,如果說我們的姐妹花組合是無法分開的,小張可能就要受累了。

  說到代碼裏,我們的一個接口內可能有好幾十個方法,有新增人員的,有修改人員的,有編輯庫存的等等,這裏我們只是想對人員進行操作,我們實現了這個接口,即使你寫空方法,也要將我們的全部方法實現一次,累不累,所以說我們應該將我們的接口合理的切分,弄成人員操作接口和庫存操作的接口等等。


 7>組合/聚合複用原則:

  某度百科沒找到,這裏強調一個事啊,有人會說沒有什麼7大設計原則,本來是6個的,沒有這個組合/聚合複用原則,其實不然,有很多OOP的原則,湊在一起,可能是6大,可能是7大,也可能“5大”,例如比較著名的SOLID,就是5個原則的縮寫。其實說到底,就是要減小代碼的重複和冗餘,使其便於理解和維護。

  組合/聚合複用原則儘量使用對象組合,而不是繼承來達到複用的目的。

  還是小張的飯店,這次呢小張引進了新菜品,紅燒肉,賣的很好,很紅火,經常是肉不夠賣的,小張的爸爸是一名市場賣肉的,小張每天都是去他爸爸的攤位購買肉,看到了生意如此的紅火,紅燒肉嚐嚐脫銷,有人就建議說,你在你店裏爲你爸爸弄一個賣肉的攤位算了,反正你紅燒肉每天都不夠賣,爲何不將攤位“繼承”到你的店裏呢。小張完全沒有心動,正常人不會這麼做的,我一個飯店,賣毛線生肉呢,我紅火的是紅燒肉,不是生肉。也就是我們的組合/聚合複用原則,我們需要生肉作爲原材料,但是並屬於我們生意的範疇,我們沒有必要把整個肉店都弄來是吧。

  小張最後一次開飯店了,因爲這是最後一個原則了,爲了慶祝小張去了足療店,走向足療一條街,選門店,開門,話不多說,直接上二樓...但精油沒有了,你說你是讓服務員下樓買一瓶好呢?還是把精油專櫃搬上來,讓精油售賣員一個個給你介紹好呢?有人說介紹的比較全面啊,那面我接下來的事,難道你也讓精油售賣員眼睜睜的看着你嗎?說回來沒有必要的事,不用繼承下來所有的吧。

  說到代碼裏,我們的數據訪問層(持久層),我們內部只要一個DB的連接就可以了,而並不需要繼承我們的DB連接類啊,直接New一個全局的就可以了吧,並沒有必要去全部拿過來。

總結:

  其實我們的那幾個原則我們的代碼中都會遇到,就是我們不太注意的問題。我們來回顧一下7個原則。

  開閉原則:擴展開,修改關。

  單一職責原則:只做一件事。

  里氏替換原則:別動你覺得沒用的屬性,你覺得畢竟是你覺得。

  迪米特原則(最少知道原則):知道的太多對你沒好處。

  接口分離原則:大變小,小專一。

  依賴倒置原則:根據接口寫代碼,沒事別自創。

  組合/聚合複用原則:用多少拿多少。

開車的方式可能有一些人不喜歡,還請見諒

最進弄了一個公衆號,小菜技術,歡迎大家的加入

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章