<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【85期】談?wù)凧ava面向?qū)ο笤O(shè)計(jì)的六大原則,中高級(jí)面試常問(wèn)!

          共 4374字,需瀏覽 9分鐘

           ·

          2020-11-11 04:16

          程序員的成長(zhǎng)之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
          關(guān)注


          閱讀本文大概需要 7 分鐘。

          來(lái)自:blog.csdn.net/Jin_Kwok/article/details/80348936

          這篇文章主要講的是面向?qū)ο笤O(shè)計(jì)中,我們應(yīng)該遵循的六大原則。只有掌握了這些原則,我們才能更好的理解設(shè)計(jì)模式。我們接下來(lái)要介紹以下6個(gè)內(nèi)容。
          • 單一職責(zé)原則——SRP

          • 開(kāi)閉原則——OCP

          • 里式替換原則——LSP

          • 依賴倒置原則——DIP

          • 接口隔離原則——ISP

          • 迪米特原則——LOD

          單一職責(zé)原則

          單一職責(zé)原則的定義是就一個(gè)類而言,應(yīng)該僅有一個(gè)引起他變化的原因。也就是說(shuō)一個(gè)類應(yīng)該只負(fù)責(zé)一件事情。如果一個(gè)類負(fù)責(zé)了方法M1,方法M2兩個(gè)不同的事情,當(dāng)M1方法發(fā)生變化的時(shí)候,我們需要修改這個(gè)類的M1方法,但是這個(gè)時(shí)候就有可能導(dǎo)致M2方法不能工作。這個(gè)不是我們期待的,但是由于這種設(shè)計(jì)卻很有可能發(fā)生。所以這個(gè)時(shí)候,我們需要把M1方法,M2方法單獨(dú)分離成兩個(gè)類。讓每個(gè)類只專心處理自己的方法。
          單一職責(zé)原則的好處如下:
          可以降低類的復(fù)雜度,一個(gè)類只負(fù)責(zé)一項(xiàng)職責(zé),這樣邏輯也簡(jiǎn)單很多 提高類的可讀性,和系統(tǒng)的維護(hù)性,因?yàn)椴粫?huì)有其他奇怪的方法來(lái)干擾我們理解這個(gè)類的含義 當(dāng)發(fā)生變化的時(shí)候,能將變化的影響降到最小,因?yàn)橹粫?huì)在這個(gè)類中做出修改。

          開(kāi)閉原則

          開(kāi)閉原則和單一職責(zé)原則一樣,是非常基礎(chǔ)而且一般是常識(shí)的原則。開(kāi)閉原則的定義是軟件中的對(duì)象(類,模塊,函數(shù)等)應(yīng)該對(duì)于擴(kuò)展是開(kāi)放的,但是對(duì)于修改是關(guān)閉的。
          當(dāng)需求發(fā)生改變的時(shí)候,我們需要對(duì)代碼進(jìn)行修改,這個(gè)時(shí)候我們應(yīng)該盡量去擴(kuò)展原來(lái)的代碼,而不是去修改原來(lái)的代碼,因?yàn)檫@樣可能會(huì)引起更多的問(wèn)題。
          這個(gè)準(zhǔn)則和單一職責(zé)原則一樣,是一個(gè)大家都這樣去認(rèn)為但是又沒(méi)規(guī)定具體該如何去做的一種原則。
          開(kāi)閉原則我們可以用一種方式來(lái)確保他,我們用抽象去構(gòu)建框架,用實(shí)現(xiàn)擴(kuò)展細(xì)節(jié)。這樣當(dāng)發(fā)生修改的時(shí)候,我們就直接用抽象了派生一個(gè)具體類去實(shí)現(xiàn)修改。

          里氏替換原則

          里氏替換原則是一個(gè)非常有用的一個(gè)概念。他的定義
          如果對(duì)每一個(gè)類型為T1的對(duì)象o1,都有類型為T2的對(duì)象o2,使得以T1定義的所有程序P在所有對(duì)象o1都替換成o2的時(shí)候,程序P的行為都沒(méi)有發(fā)生變化,那么類型T2是類型T1的子類型。
          這樣說(shuō)有點(diǎn)復(fù)雜,其實(shí)有一個(gè)簡(jiǎn)單的定義
          所有引用基類的地方必須能夠透明地使用其子類的對(duì)象。
          里氏替換原則通俗的去講就是:子類可以去擴(kuò)展父類的功能,但是不能改變父類原有的功能。他包含以下幾層意思:
          • 子類可以實(shí)現(xiàn)父類的抽象方法,但是不能覆蓋父類的非抽象方法。

          • 子類可以增加自己獨(dú)有的方法。

          • 當(dāng)子類的方法重載父類的方法時(shí)候,方法的形參要比父類的方法的輸入?yún)?shù)更加寬松。

          • 當(dāng)子類的方法實(shí)現(xiàn)父類的抽象方法時(shí),方法的返回值要比父類更嚴(yán)格。

          里氏替換原則之所以這樣要求是因?yàn)槔^承有很多缺點(diǎn),他雖然是復(fù)用代碼的一種方法,但同時(shí)繼承在一定程度上違反了封裝。父類的屬性和方法對(duì)子類都是透明的,子類可以隨意修改父類的成員。這也導(dǎo)致了,如果需求變更,子類對(duì)父類的方法進(jìn)行一些復(fù)寫的時(shí)候,其他的子類無(wú)法正常工作。所以里氏替換法則被提出來(lái)。
          確保程序遵循里氏替換原則可以要求我們的程序建立抽象,通過(guò)抽象去建立規(guī)范,然后用實(shí)現(xiàn)去擴(kuò)展細(xì)節(jié),這個(gè)是不是很耳熟,對(duì),里氏替換原則和開(kāi)閉原則往往是相互依存的。

          依賴倒置原則

          依賴倒置原則指的是一種特殊的解耦方式,使得高層次的模塊不應(yīng)該依賴于低層次的模塊的實(shí)現(xiàn)細(xì)節(jié)的目的,依賴模塊被顛倒了。這也是一個(gè)讓人難懂的定義,他可以簡(jiǎn)單來(lái)說(shuō)就是
          高層模塊不應(yīng)該依賴底層模塊,兩者都應(yīng)該依賴其抽象 抽象不應(yīng)該依賴細(xì)節(jié) 細(xì)節(jié)應(yīng)該依賴抽象
          在Java 中抽象指的是接口或者抽象類,兩者皆不能實(shí)例化。而細(xì)節(jié)就是實(shí)現(xiàn)類,也就是實(shí)現(xiàn)了接口或者繼承了抽象類的類。他是可以被實(shí)例化的。高層模塊指的是調(diào)用端,底層模塊是具體的實(shí)現(xiàn)類。在Java中,依賴倒置原則是指模塊間的依賴是通過(guò)抽象來(lái)發(fā)生的,實(shí)現(xiàn)類之間不發(fā)生直接的依賴關(guān)系,其依賴關(guān)系是通過(guò)接口是來(lái)實(shí)現(xiàn)的。這就是俗稱的面向接口編程。
          我們下面有一個(gè)例子來(lái)講述這個(gè)問(wèn)題。這個(gè)例子是工人用錘子來(lái)修理東西。我們的代碼如下:
          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());
          ????}
          }
          這個(gè)是一個(gè)很簡(jiǎn)單的例子,但是如果我們要新增加一個(gè)功能,工人用 螺絲刀來(lái)修理東西,在這個(gè)類,我們發(fā)現(xiàn)是很難做的。因?yàn)槲覀僕orker類依賴于一個(gè)具體的實(shí)現(xiàn)類Hammer。所以我們用到面向接口編程的思想,改成如下的代碼:
          public?interface?Tools?{
          ????public?String?function();
          }
          然后我們的Worker是通過(guò)這個(gè)接口來(lái)于其他細(xì)節(jié)類進(jìn)行依賴。代碼如下:
          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類實(shí)現(xiàn)這個(gè)接口
          public?class?Hammer?implements?Tools{
          ????public?String?function(){
          ????????return?"用錘子修理東西";
          ????}
          }

          public?class?Screwdriver?implements?Tools{
          ????@Override
          ????public?String?function()?{
          ????????return?"用螺絲刀修理東西";
          ????}
          }
          這樣,通過(guò)面向接口編程,我們的代碼就有了很高的擴(kuò)展性,降低了代碼之間的耦合度,提高了系統(tǒng)的穩(wěn)定性。

          接口隔離原則

          接口隔離原則的定義是
          客戶端不應(yīng)該依賴他不需要的接口
          換一種說(shuō)法就是類間的依賴關(guān)系應(yīng)該建立在最小的接口上。這樣說(shuō)好像更難懂。我們通過(guò)一個(gè)例子來(lái)說(shuō)明。我們知道在Java中一個(gè)具體類實(shí)現(xiàn)了一個(gè)接口,那必然就要實(shí)現(xiàn)接口中的所有方法。如果我們有一個(gè)類A和類B通過(guò)接口I來(lái)依賴,類B是對(duì)類A依賴的實(shí)現(xiàn),這個(gè)接口I有5個(gè)方法。但是類A與類B只通過(guò)方法1,2,3依賴,然后類C與類D通過(guò)接口I來(lái)依賴,類D是對(duì)類C依賴的實(shí)現(xiàn)但是他們卻是通過(guò)方法1,4,5依賴。那么是必在實(shí)現(xiàn)接口的時(shí)候,類B就要有實(shí)現(xiàn)他不需要的方法4和方法5 而類D就要實(shí)現(xiàn)他不需要的方法2,和方法3。這簡(jiǎn)直就是一個(gè)災(zāi)難的設(shè)計(jì)。
          所以我們需要對(duì)接口進(jìn)行拆分,就是把接口分成滿足依賴關(guān)系的最小接口,類B與類D不需要去實(shí)現(xiàn)與他們無(wú)關(guān)接口方法。比如在這個(gè)例子中,我們可以把接口拆成3個(gè),第一個(gè)是僅僅由方法1的接口,第二個(gè)接口是包含2,3方法的,第三個(gè)接口是包含4,5方法的。這樣,我們的設(shè)計(jì)就滿足了接口隔離原則。
          以上這些設(shè)計(jì)思想用英文的第一個(gè)字母可以組成SOLID ,滿足這個(gè)5個(gè)原則的程序也被稱為滿足了SOLID準(zhǔn)則。

          迪米特原則

          迪米特原則也被稱為最小知識(shí)原則,他的定義
          一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象保持最小的了解。
          因?yàn)轭惻c類之間的關(guān)系越密切,耦合度越大,當(dāng)一個(gè)類發(fā)生改變時(shí),對(duì)另一個(gè)類的影響也越大,所以這也是我們提倡的軟件編程的總的原則:低耦合,高內(nèi)聚。迪米特法則還有一個(gè)更簡(jiǎn)單的定義
          只與直接的朋友通信。首先來(lái)解釋一下什么是直接的朋友:每個(gè)對(duì)象都會(huì)與其他對(duì)象有耦合關(guān)系,只要兩個(gè)對(duì)象之間有耦合關(guān)系,我們就說(shuō)這兩個(gè)對(duì)象之間是朋友關(guān)系。耦合的方式很多,依賴、關(guān)聯(lián)、組合、聚合等。其中,我們稱出現(xiàn)成員變量、方法參數(shù)、方法返回值中的類為直接的朋友,而出現(xiàn)在局部變量中的類則不是直接的朋友。也就是說(shuō),陌生的類最好不要作為局部變量的形式出現(xiàn)在類的內(nèi)部。
          這里我們可以用一個(gè)現(xiàn)實(shí)生活中的例子來(lái)講解一下。比如我們需要一張CD,我們可能去音像店去問(wèn)老板有沒(méi)有我們需要的那張CD,老板說(shuō)現(xiàn)在沒(méi)有,等有的時(shí)候你們來(lái)拿就行了。在這里我們不需要關(guān)心老板是從哪里,怎么獲得的那張CD,我們只和老板(直接朋友)溝通,至于老板從他的朋友那里通過(guò)何種條件得到的CD,我們不關(guān)心,我們不和老板的朋友(陌生人)進(jìn)行通信,這個(gè)就是迪米特的一個(gè)應(yīng)用。說(shuō)白了,就是一種中介的方式。我們通過(guò)老板這個(gè)中介來(lái)和真正提供CD的人發(fā)生聯(lián)系。

          總結(jié)

          到這里,面向?qū)ο蟮牧笤瓌t,就寫完了。我們看出來(lái),這些原則其實(shí)都是應(yīng)對(duì)不斷改變的需求。每當(dāng)需求變化的時(shí)候,我們利用這些原則來(lái)使我們的代碼改動(dòng)量最小,而且所造成的影響也是最小的。
          但是我們?cè)诳催@些原則的時(shí)候,我們會(huì)發(fā)現(xiàn)很多原則并沒(méi)有提供一種公式化的結(jié)論,而即使提供了公式化的結(jié)論的原則也只是建議去這樣做。這是因?yàn)?,這些設(shè)計(jì)原則本來(lái)就是從很多實(shí)際的代碼中提取出來(lái)的,他是一個(gè)經(jīng)驗(yàn)化的結(jié)論。怎么去用它,用好他,就要依靠設(shè)計(jì)者的經(jīng)驗(yàn)。
          否則一味者去使用設(shè)計(jì)原則可能會(huì)使代碼出現(xiàn)過(guò)度設(shè)計(jì)的情況。大多數(shù)的原則都是通過(guò)提取出抽象和接口來(lái)實(shí)現(xiàn),如果發(fā)生過(guò)度的設(shè)計(jì),就會(huì)出現(xiàn)很多抽象類和接口,增加了系統(tǒng)的復(fù)雜度。讓本來(lái)很小的項(xiàng)目變得很龐大,當(dāng)然這也是Java的特性(任何的小項(xiàng)目都會(huì)做成中型的項(xiàng)目)。

          推薦閱讀:

          【84期】面試中設(shè)計(jì)模式能問(wèn)些什么?比如說(shuō)一下三種單例模式實(shí)現(xiàn)

          【83期】面試被問(wèn)到了Redis和MongoDB的區(qū)別?看這里就對(duì)了

          【82期】面試中被問(wèn)到SQL優(yōu)化,看這篇就對(duì)了!

          5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機(jī),樹(shù)莓派,等等。在公眾號(hào)內(nèi)回復(fù)「2048」,即可免費(fèi)獲?。?!

          微信掃描二維碼,關(guān)注我的公眾號(hào)

          朕已閱?

          瀏覽 32
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩v欧美 | 99超碰在线免费观看 | 看日本黄色片 | 无码国产精品一区二区色情男同 | 亚洲一区二区无码 |