現(xiàn)在編程的主流語(yǔ)言基本上都是面向?qū)ο蟮钠TH鏑#,C++早处,JAVA湾蔓。我們?cè)谑褂脮r(shí),已經(jīng)構(gòu)造了一個(gè)個(gè)的類(lèi)砌梆。但是往往由于我們?cè)陬?lèi)內(nèi)部或外部的設(shè)計(jì)上存在種種問(wèn)題默责,導(dǎo)致盡管是面向?qū)ο蟮恼Z(yǔ)言,卻是面向過(guò)程的邏輯咸包,甚至維護(hù)起來(lái)異常困難桃序。每次增加或修改功能都要改動(dòng)很多的代碼,如履薄冰诉儒。而面向?qū)ο蟮牧笤瓌t主要的目的葡缰,就是我們?nèi)绾卧O(shè)計(jì)類(lèi),更能很好的利用面向?qū)ο蟮奶匦浴?br>
1)單一職責(zé)原則
一個(gè)類(lèi)永遠(yuǎn)只有一個(gè)職責(zé)忱反。
一套軟件就像是一個(gè)團(tuán)隊(duì)泛释,每個(gè)類(lèi)就是團(tuán)隊(duì)中的一個(gè)成員。團(tuán)隊(duì)如果想穩(wěn)定的發(fā)展温算。這些類(lèi)就要各司其職怜校,分工明確。如果類(lèi)之間的功能出現(xiàn)了混淆注竿,那么軟件的整體結(jié)構(gòu)就會(huì)非常的混亂茄茁。就像管理學(xué)中的一句話(huà),如果一個(gè)職責(zé)由每個(gè)員工負(fù)責(zé)巩割,那么這個(gè)職責(zé)就沒(méi)有員工在負(fù)責(zé)裙顽。 這個(gè)原則的概念非常簡(jiǎn)單,也是非承福基礎(chǔ)的愈犹。很多人盡管沒(méi)有學(xué)習(xí)過(guò)面向?qū)ο蟮乃枷耄墙?jīng)常寫(xiě)代碼之后也會(huì)不自覺(jué)的遵守這個(gè)原則。 Ps:在遵循單一職責(zé)原則的時(shí)候漩怎,常常會(huì)遇到職責(zé)擴(kuò)散的問(wèn)題勋颖。什么是職責(zé)擴(kuò)散呢?這里簡(jiǎn)單說(shuō)下勋锤,在日志生活中饭玲,我們?cè)诜诸?lèi)職責(zé)時(shí),發(fā)現(xiàn)很多平常不受重視的職責(zé)叁执,但是這些職責(zé)又不能忽視茄厘。于是就依次累加,最后分起類(lèi)來(lái)會(huì)無(wú)窮無(wú)盡(有興趣的讀者可以參考下長(zhǎng)尾定理)谈宛。為了解決這種問(wèn)題蚕断,我們就需要有一些類(lèi),他的職責(zé)比較綜合(類(lèi)似于“其它”)入挣。類(lèi)似于一個(gè)幫助類(lèi)亿乳。但是這個(gè)類(lèi)又不能太復(fù)雜了,否則我們就應(yīng)該考慮怎么把這個(gè)類(lèi)分離開(kāi)來(lái)径筏。究竟這個(gè)類(lèi)的復(fù)雜程度到了什么時(shí)候情況下葛假,我們就應(yīng)該拆分呢?這個(gè)需要程序員根據(jù)軟件自身的復(fù)雜情況來(lái)判斷滋恬,沒(méi)有一個(gè)統(tǒng)一的標(biāo)準(zhǔn)聊训。
2) 里氏替換原則
“Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.”
——“繼承必須確保超類(lèi)所擁有的性質(zhì)在子類(lèi)中仍然成立“
這個(gè)原則主要是為了體現(xiàn)面向?qū)ο蟮摹袄^承”特征來(lái)提出的。 它的主旨就是恢氯,能夠使用基類(lèi)的地方带斑,必然也能夠透明的使用其子類(lèi),并且保證不會(huì)出錯(cuò)勋拟。為了保證這種透明的無(wú)差別的使用勋磕,子類(lèi)在使用時(shí)不應(yīng)該隨意的重寫(xiě)父類(lèi)已經(jīng)定義好的非抽象的方法。因?yàn)檫@些非抽象方法敢靡,類(lèi)似于某種職能或契約挂滓,當(dāng)父類(lèi)保持這種約定時(shí),子類(lèi)也應(yīng)該遵循并保證該特性啸胧,而非修改該特性赶站。 我們?cè)趯?xiě)代碼的時(shí)候,如果一個(gè)參數(shù)設(shè)定的是基類(lèi)(或接口纺念、抽象類(lèi))贝椿,那么我們傳送子類(lèi)進(jìn)去,一樣可以正常使用陷谱。因?yàn)榛?lèi)相對(duì)于父類(lèi)烙博,只是一個(gè)更豐富,更具體,更詳細(xì)的表現(xiàn)形式习勤。而不應(yīng)該出現(xiàn),傳入父類(lèi)運(yùn)行某種方法沒(méi)有問(wèn)題焙格,可是傳入子類(lèi)運(yùn)行時(shí)就報(bào)錯(cuò)了图毕。這在日常生活中也可以理解,汽車(chē)作為父類(lèi)眷唉,他下面有卡車(chē)予颤、轎車(chē)。轎車(chē)下邊又有兩廂冬阳,三廂等不同的繼承蛤虐。但是無(wú)論是哪種汽車(chē)(父類(lèi))的職能,對(duì)于他的子類(lèi)(卡車(chē)或轎車(chē))都應(yīng)該具有相同的職能肝陪,而不是相反的職能驳庭。以至于子類(lèi)的子類(lèi)(本例中是兩廂轎車(chē))也應(yīng)該擁有汽車(chē)一致的功能。
我們?cè)趯?xiě)代碼中氯窍,很容易出現(xiàn)復(fù)寫(xiě)了父類(lèi)的方法后饲常,父類(lèi)的方法發(fā)生了改動(dòng),而未考慮到子類(lèi)的方法也需要作出相應(yīng)的改動(dòng)狼讨,導(dǎo)致代碼出現(xiàn)錯(cuò)誤贝淤。 通俗一點(diǎn),可以理解為子類(lèi)是遺傳自父類(lèi)的政供。他在各種職能上也應(yīng)該一脈相承自父類(lèi)播聪。而不應(yīng)該隨意改變。
Ps 為什么要叫里氏替換原則呢布隔?這是因?yàn)樽钤缣岢鲞@個(gè)理論的人姓里L(fēng)iskov离陶。這是計(jì)算機(jī)中少有的以姓氏命名的東西。
3)最少知道原則
Only talk to your immediate friends衅檀。(已經(jīng)第二次引用英文枕磁,是不是很厲害23333)
永遠(yuǎn)只和你的朋友交流。
我們?cè)趯W(xué)習(xí)編程的初期术吝,都會(huì)有人告訴我們要遵循“高內(nèi)聚计济,低耦合”。而OO中也將“封裝”作為對(duì)象的基本特征之一排苍。最少知道原則其實(shí)體現(xiàn)的就是“高內(nèi)聚沦寂,低耦合”這句話(huà)。
(1)低耦合:一個(gè)類(lèi)對(duì)于自己依賴(lài)的類(lèi)淘衙,知道的越少越好传藏。不要讓一個(gè)類(lèi)依賴(lài)過(guò)多的類(lèi)。否則這個(gè)類(lèi)很容受外界的影響,并且因?yàn)檫@種影響要改變自身的代碼(自身要適應(yīng))毯侦。
(2)高內(nèi)聚:將實(shí)現(xiàn)邏輯都封裝在類(lèi)的內(nèi)部哭靖,對(duì)public方法以外的信息,不輕易暴露給外界侈离。這是由于public對(duì)外后试幽,相當(dāng)于是一種契約,一種許諾卦碾。你要再后邊的實(shí)現(xiàn)中铺坞,不斷的去兼容這種public,以防止調(diào)用它的代碼不會(huì)報(bào)錯(cuò)洲胖。 上面這樣說(shuō)济榨,可能有點(diǎn)抽象,這里舉個(gè)例子绿映。在很多人對(duì)另一方的要求擒滑,都有一條,社會(huì)關(guān)系不要復(fù)雜叉弦。為什么會(huì)這樣呢橘忱?因?yàn)橐粋€(gè)人如果他和外界的關(guān)系越復(fù)雜,他就越不穩(wěn)定卸奉,不怕人找事钝诚,就怕事找人¢茫或許他的本性是好的凝颇,但是周邊的龍魚(yú)混雜,三天兩頭的總會(huì)有事疹鳄。避免這種問(wèn)題的最好辦法拧略,就是一開(kāi)始就做一個(gè)安靜的美男子。
4)接口隔離原則
一個(gè)類(lèi)對(duì)于另外一個(gè)類(lèi)的依賴(lài)應(yīng)該建立在最小的接口上瘪弓。
一個(gè)接口定義的過(guò)于臃腫垫蛆,則代表他的每一個(gè)實(shí)現(xiàn)類(lèi)都要考慮所有的實(shí)現(xiàn)邏輯。如果一個(gè)類(lèi)實(shí)現(xiàn)了某個(gè)接口腺怯,也就是說(shuō)這個(gè)類(lèi)承載了這個(gè)接口所有的功能袱饭,維護(hù)這些功能成為了自己的職責(zé)。這就無(wú)形中增加了一個(gè)類(lèi)的負(fù)擔(dān)呛占。
這里有兩點(diǎn)需要說(shuō)明一下:
(1)接口定義的小虑乖,但是要有限度。對(duì)接口細(xì)化可以增加靈活性晾虑,但是過(guò)度細(xì)化則會(huì)使設(shè)計(jì)復(fù)雜化疹味。同時(shí)接口的使用率不高仅叫,提高了代碼的維護(hù)成本。這種極端的體現(xiàn)就是每個(gè)接口只含有一個(gè)方法糙捺,這顯然是不合適的诫咱。
(2)接口隔離原則和單一原則的區(qū)別
共同點(diǎn):都是盡可能的縮小涉及的范圍。
不同點(diǎn):?jiǎn)我辉瓌t主要是指封裝性洪灯。他針對(duì)的是一個(gè)類(lèi)坎缭、一個(gè)方法,是從對(duì)象的角度考慮的婴渡。而接口隔離原則是指類(lèi)之間的耦合應(yīng)該保持的一個(gè)度。他針對(duì)的是類(lèi)(對(duì)象)和類(lèi)(對(duì)象)之間的關(guān)系凯亮。如果說(shuō)單一原則指的是思想單純边臼,那么接口隔離指的就是社會(huì)關(guān)系簡(jiǎn)單啦。
5)依賴(lài)置換原則
這個(gè)原則的名字比較唬人假消,我們先看看他的內(nèi)容究竟是什么柠并。在設(shè)計(jì)模式中對(duì)該原則有兩句經(jīng)典的描述:
(1)高層模塊不應(yīng)該依賴(lài)底層模塊。兩者都應(yīng)該依賴(lài)抽象富拗。
(2)抽象不應(yīng)該依賴(lài)細(xì)節(jié)臼予,細(xì)節(jié)應(yīng)該依賴(lài)抽象。
這兩句話(huà)的含義是:高層模塊不應(yīng)該依賴(lài)底層模塊啃沪。兩者應(yīng)該通過(guò)抽象的東西進(jìn)行關(guān)系鏈接(抽象的東西是指接口或者抽象類(lèi))粘拾。其次抽象類(lèi)或者一個(gè)接口不應(yīng)該依賴(lài)某個(gè)實(shí)現(xiàn)類(lèi)。而這些實(shí)現(xiàn)類(lèi)反而應(yīng)該依賴(lài)于這個(gè)抽象類(lèi)的設(shè)定创千。
通俗一點(diǎn)的說(shuō)法就是缰雇,模塊之間不應(yīng)該直接產(chǎn)生調(diào)用關(guān)系(這是舊有的調(diào)用關(guān)系),兩者應(yīng)該通過(guò)面向接口(或者理解為面向設(shè)定的契約)進(jìn)行編程追驴。而這些契約和接口更不應(yīng)該以來(lái)自底層模塊而設(shè)定械哟。這些底層模塊反而應(yīng)該遵守這些契約。因?yàn)槠跫s(抽象類(lèi)殿雪、接口)相對(duì)于哪些實(shí)現(xiàn)代碼暇咆,更不會(huì)改變,也就是更穩(wěn)定丙曙。所以依賴(lài)置換原則又叫作面向接口編程或面向契約編程爸业。本意就是調(diào)整原來(lái)的依賴(lài)關(guān)系,重行進(jìn)行了設(shè)定亏镰。
6)開(kāi)閉原則
開(kāi)閉原則是指:一個(gè)軟件沃呢、一套系統(tǒng)在開(kāi)發(fā)完成后,當(dāng)有增加或修改需求時(shí)拆挥,應(yīng)該對(duì)拓展代碼打開(kāi)薄霜,對(duì)修改原有代碼關(guān)閉某抓。
類(lèi)一旦確定,就不應(yīng)該再對(duì)其功能發(fā)生修改惰瓜。這是面向?qū)ο笤O(shè)計(jì)中否副,最重要最核心的原則。方案發(fā)布后崎坊,我們最擔(dān)心的是什么备禀?就是需求的變化,而需求一旦有變化奈揍,就要修改代碼曲尸。大部分的bug往往就是這時(shí)候引入的。因?yàn)樾薷拇a時(shí)男翰,我們往往將重點(diǎn)放在另患,如何解決當(dāng)前bug上,反而沒(méi)有注意因?yàn)檫@個(gè)修改蛾绎,對(duì)原有設(shè)計(jì)的影響昆箕。
這條原則沒(méi)有具體的指導(dǎo)要求,是前邊五條原則的根本租冠。
ps鹏倘,這六個(gè)面向?qū)ο蟮脑瓌t,并不是是和否的問(wèn)題顽爹,也不是遵守和不遵守的問(wèn)題纤泵。而是遵守的多和遵守的少的問(wèn)題。我在文中也多次強(qiáng)調(diào)镜粤,我們?cè)谠O(shè)計(jì)時(shí)夕吻,應(yīng)該注意把握一個(gè)度。誠(chéng)然盡可能的遵守這些原則繁仁,會(huì)使代碼維護(hù)起來(lái)更容易涉馅。但是維護(hù)粒度過(guò)細(xì),所需要的設(shè)計(jì)和開(kāi)發(fā)成本成倍增加黄虱,這顯然是舍本逐末的稚矿。如圖,面向?qū)ο箝_(kāi)發(fā)原則可以從以下這個(gè)坐標(biāo)圖展示捻浦,不論是哪個(gè)維度晤揣,他的值都不應(yīng)該過(guò)滿(mǎn),甚至溢出朱灿,當(dāng)然也不能很低昧识,保持一個(gè)適當(dāng)?shù)亩燃纯伞?/p>