国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

JAVA初探設計模式的六大原則

發(fā)布時(shí)間:2021-07-06 11:12 來(lái)源:腳本之家 閱讀:0 作者:外婆的 欄目: 開(kāi)發(fā)技術(shù)

目錄

前言

我想用貼近生活的語(yǔ)句描述一下自己對六種原則的理解。也就是不做專(zhuān)業(yè)性的闡述,而是描述一種自己學(xué)習后的理解和感受,因為能力一般而且水平有限,也許舉的例子不盡妥當,還請諒解原本我是想用JavaScript編寫(xiě)的,但是JavaScript到現在還沒(méi)有提出接口的概念,而用TypeScript寫(xiě)又感覺(jué)普及度還不算特別高,所以還是決定用Java語(yǔ)言編寫(xiě)

首先要提的是:六大原則的靈魂是面向接口,以及如何合理地運用接口

P1.單一職責原則(Single Responsibility Principle)

應該有且僅有一個(gè)原因引起類(lèi)的變更(There should never be more than one reason for a class to change)。為了達到這個(gè)目標,我們需要對類(lèi)和業(yè)務(wù)邏輯進(jìn)行拆分。劃分到合適的粒度,讓這些各自執行單一職責的類(lèi),各司其職。讓每個(gè)類(lèi)盡量行使單一的功能,實(shí)現“高內聚”,這個(gè)結果也使得類(lèi)和類(lèi)之間不會(huì )有過(guò)多冗余的聯(lián)系,從而“低耦合”。比如我們現在有了這樣一個(gè)類(lèi)

public class People {
    public void playCnBlogs () {
        System.out.println("刷博客");
    }
    public void doSports () {
        System.out.println("打乒乓球");
    }
    public void work () {
        System.out.println("工作");
    }
}

現在看起來(lái)有點(diǎn)混亂,因為這個(gè)類(lèi)里面混合了三個(gè)職責:

  • 刷博客園,這是博主的職責
  • 打乒乓球,這是業(yè)余運動(dòng)愛(ài)好者的職責
  • 工作,這是“普普通通上班族”的職責

OK,正如你所見(jiàn),既然我們要遵循單一職責,那么怎么做呢?當然是要拆分了我們要根據接口去拆,拆分成三個(gè)接口去約束People類(lèi)(不是把People類(lèi)拆了哈)

// 知乎er
public interface Blogger {
    public void playCnBlogs();
}
// 上班族
public interface OfficeWorkers {
    public void work();
}
// 業(yè)余運動(dòng)愛(ài)好者
public interface AmateurPlayer {
    public void doSports();
}

然后在People中繼承這幾個(gè)接口

public class People implements Blogger,AmateurPlayer,OfficeWorkers{
    public void playCnBlogs () {
        System.out.println("刷博客園");
    }
    public void doSports () {
        System.out.println("打乒乓球");
    }
    public void work () {
        System.out.println("工作");
    }
}

最后創(chuàng )建實(shí)例運行一下

public class Index {
    public static  void main (String args []) {
        People people = new People();
        Blogger blogger = new People();
        blogger.playCnBlogs(); // 輸出:刷博客園
        OfficeWorkers workers = new People();
        workers.work(); // 輸出: 工作
        AmateurPlayer players = new People();
        players.doSports(); // 輸出:打乒乓球
    }
}

備注:這個(gè)原則不是死的,而是活的,在實(shí)際開(kāi)發(fā)中當然還要和業(yè)務(wù)相結合,不會(huì )純粹為了理論貫徹單一職責,就像數據開(kāi)發(fā)時(shí)候,不會(huì )完全遵循“三大范式”,而是允許一定冗余的

P2.里氏替換原則(liskov substitution principle)

里氏替換原則,一種比較好的理解方式是: 所有引用基類(lèi)的地方必須能透明地使用其子類(lèi)的對象。 換句話(huà)說(shuō),子類(lèi)必須完全實(shí)現父類(lèi)的功能。凡是父類(lèi)出現的地方,就算完全替換成子類(lèi)也不會(huì )有什么問(wèn)題。以上描述來(lái)自《設計模式之禪》,剛開(kāi)始看的時(shí)候我有些疑惑,因為一開(kāi)始覺(jué)得:只要繼承了父類(lèi)不都可以調用父類(lèi)的方法嗎?為什么還會(huì )有里氏替換所要求的:子類(lèi)必須完全實(shí)現父類(lèi)的功能呢, 難不成繼承的子類(lèi)還可以主動(dòng)“消除”父類(lèi)的方法?還真可以,請看

父類(lèi)

public abstract class Father {
    // 認真工作
    public abstract void work();
    // 其他方法
}

子類(lèi)

public class Son extends Father {
    @Override
    public void work() {
     // 我實(shí)現了爸爸的work方法,旦我什么也不做!
    }
}

子類(lèi)雖然表面上實(shí)現了父類(lèi)的方法,但是他實(shí)際上并沒(méi)有實(shí)現父類(lèi)要求的邏輯。里氏替換原則要求我們避免這種“塑料父子情”,如果出現子類(lèi)不得不脫離父類(lèi)方法范圍的情況, 采取其他方式處理,詳情參考《設計模式之禪》

(其實(shí)個(gè)人覺(jué)得《禪》的作者其實(shí)講的“父類(lèi)”其實(shí)著(zhù)重指的是抽象類(lèi))

P3.依賴(lài)倒置原則 (dependence inversion principle)

很多文章闡述依賴(lài)倒置原則都會(huì )闡述為三個(gè)方面

  • 高層的模塊不應該依賴(lài)于低層的模塊,這兩者都應該依賴(lài)于其抽象
  • 抽象不應該依賴(lài)細節
  • 細節應該依賴(lài)抽象

換句話(huà)說(shuō), 高層次的類(lèi)不應該依賴(lài)于,或耦合于低層次的類(lèi),相反,這兩者都應該通過(guò)相關(guān)的接口去實(shí)現。要面向接口編程,而不是面向實(shí)現編程,所以編程的時(shí)候并不是按照符合我們邏輯思考的“依賴(lài)關(guān)系”去編程掉的,這種不符,就是依賴(lài)倒置舉個(gè)例子,類(lèi)好比是道德,接口好比是法律。道德呢,有上層的也有下層的,春秋時(shí)代,孔圣人提出了上層道德理論:“仁”的思想,并進(jìn)一步細化為低層道德理論:“三綱五?!保ǜ邔幽K和底層模塊),想要以此規約眾生,實(shí)現天下大同??墒悄魏蚊癖姷牡赖陆K究還是靠不?。](méi)有接口約束的類(lèi),可能被混亂修改),何況道德標準是會(huì )隨物質(zhì)經(jīng)濟的變化而變化的,孔子時(shí)代和我們今天的已經(jīng)大有不同了。(類(lèi)可能會(huì )發(fā)生變化)所以才需要法律來(lái)進(jìn)一步框定和要求道德。(我們用接口來(lái)約束和維護“類(lèi)”,就好比用法律來(lái)維護和規約道德一樣。)假如未來(lái)道德倫理的標桿發(fā)生了變化,肯定是先修繕?lè )?,然后再次反向規制和落?shí)道德(面向接口編程,而不是面向實(shí)現編程)。我們看下下面沒(méi)有遵循依賴(lài)倒置原則的代碼是怎樣的,我們設計了兩個(gè)類(lèi):Coder類(lèi)和Linux類(lèi),并且讓它們之間產(chǎn)生交互:Coder對象的develop方法接收Linux對象并且輸出系統名

// 底層模塊1:開(kāi)發(fā)者
public class Coder {
    public void develop (Linux linux) {
        System.out.printf("開(kāi)發(fā)者正在%s系統上進(jìn)行開(kāi)發(fā)%n",linux.getSystemName());
    }
}
// 底層模塊2:Linux操作系統
public class Linux {
    public String name;
    public Linux(String name){
        this.name = name;
    }
    public String getSystemName () {
        return this.name;
    }
}
// 高層模塊
public class Index {
    public static  void main (String args []) {
        Coder coder = new Coder();
        Linux ubuntu = new Linux("ubuntu系統"); // ubuntu是一種linux操作系統
        coder.develop(ubuntu);
    }
}

輸出

開(kāi)發(fā)者正在ubuntu系統系統上進(jìn)行開(kāi)發(fā) 

但是我們能發(fā)現其中的問(wèn)題:

操作系統不僅僅有Linux家族,還有Windows家族,如果我們現在需要讓開(kāi)發(fā)者在windows系統上寫(xiě)代碼怎么辦呢? 我們可能要新建一個(gè)Windows類(lèi),但是問(wèn)題來(lái)了,Code.develop方法的入參數類(lèi)型是Linux,這樣以來(lái)改造就變得很麻煩。讓我們利用依賴(lài)倒置原則改造一下,我們定義OperatingSystem接口,將windows/Linux抽象成操作系統,這樣,OperatingSystem類(lèi)型的入參就可以接收Windows或者Linux類(lèi)型的參數了

// 程序員接口
public interface Programmer {
    public void develop (OperatingSystem OS);
}
// 操作系統接口
public interface OperatingSystem {
    public String getSystemName ();
}
// 低層模塊:Linux操作系統
public class Linux implements  OperatingSystem{
    public String name;
    public Linux (String name) {
        this.name = name;
    }
    @Override
    public String getSystemName() {
        return this.name;
    }
}
// 低層模塊:Window操作系統
public class Window implements OperatingSystem {
    String name;
    public Window (String name) {
        this.name = name;
    }
    @Override
    public String getSystemName() {
        return this.name;
    }
}
// 低層模塊:開(kāi)發(fā)者
public class Coder implements Programmer{
    @Override
    public void develop(OperatingSystem OS) {
        System.out.printf("開(kāi)發(fā)者正在%s系統上進(jìn)行開(kāi)發(fā)%n",OS.getSystemName());
    }
}
// 高層模塊:測試用
public class Index {
    public static  void main (String args []) {
        Programmer coder = new Coder();
        OperatingSystem ubuntu = new Linux("ubuntu系統"); // ubuntu是一種linux操作系統
        OperatingSystem windows10 = new Window("windows10系統"); // windows10
        coder.develop(ubuntu);
        coder.develop(windows10);
    }
}

雖然接口的加入讓代碼多了一些,但是現在擴展性變得良好多了,即使有新的操作系統加入進(jìn)來(lái),Coder.develop也能處理

P4. 接口隔離原則(interface segregation principle)

接口隔離原則的要求是:類(lèi)間的依賴(lài)關(guān)系應該建立在最小的接口上。這個(gè)原則又具體分為兩點(diǎn)

1.接口要足夠細化,當然了,這會(huì )讓接口的數量變多,但是每個(gè)接口會(huì )具有更加明確的功能

2.在1的前提下,類(lèi)應該依賴(lài)于“最小”的接口上

舉個(gè)例子,中秋節其實(shí)只過(guò)了一個(gè)多月,現在假設你有一大盒“五仁月餅”想帶回家喂豬,但是無(wú)奈的是包包太小放不下,而且一盒沉重的月餅對瘦弱的你是個(gè)沉重的負擔。這個(gè)時(shí)候,我們可以把月餅盒子拆開(kāi),選出一部分自己需要(wei zhu)的月餅,放進(jìn)包包里就好啦,既輕便又靈活。還是上代碼吧,比如我們有這樣一個(gè)Blogger的接口,里面涵蓋了一些可能的行為。大多數博客用戶(hù)會(huì )保持友善,同時(shí)根據自己的專(zhuān)業(yè)知識認真寫(xiě)文章。但也有少數的人會(huì )把生活中的負面能量帶到網(wǎng)絡(luò )中

public interface Blogger {
    // 認真撰文
    public void seriouslyWrite();
    // 友好評論
    public void friendlyComment();
    // 無(wú)腦抬杠
    public void argue();
    // 鍵盤(pán)攻擊
    public void keyboardAttack ();
}

我們發(fā)現,這個(gè)接口可以進(jìn)一步拆分成兩個(gè)接口,分別命名為PositiveBlogger,NegativeBlogger。這樣,我們就把接口細化到了一個(gè)合理的范圍

public interface PositiveBlogger {
    // 認真撰文
    public void seriouslyWrite();
    // 友好評論
    public void friendlyComment();
}

public interface NegativeBlogger {
    // 無(wú)腦抬杠
    public void argue();
    // 鍵盤(pán)攻擊
    public void keyboardAttack ();
}

>> 備注:妥善處理 單一職責原則 和 接口隔離原則的關(guān)系事實(shí)上,有兩點(diǎn)要說(shuō)明一下

1.單一職責原則和接口隔離原則雖然看起來(lái)有點(diǎn)像,好像都是拆分,但是其實(shí)側重點(diǎn)是不一樣的,“職責”的粒度其實(shí)是比“隔離接口”的粒度要大的

2.基于1中闡述的原因,其實(shí) 單一職責原則 和 接口隔離原則是可能會(huì )產(chǎn)生沖突的,因為接口隔離原則要求粒度盡可能要細,但是單一職責原則卻不同,它要求拆分既不能過(guò)粗,但也不能過(guò)細,如果把原本單一職責的接口分成了“兩個(gè)0.5職責的接口”,那么這就是單一職責所不能允許的了。

3.當兩者沖突時(shí),優(yōu)先遵循 單一職責原則

P5.迪米特原則 (law of demeter)

迪米特原則又叫最少知道原則,在實(shí)現功能的前提下,一個(gè)對象接觸的其他對象應該盡可能少,也即類(lèi)和類(lèi)之間的耦合度要低。舉個(gè)例子,我們經(jīng)常說(shuō)要“減少無(wú)效社交”,不要總是一昧的以交朋友的數量衡量自己的交際能力,否則會(huì )讓自己很累的,也會(huì )難以打理好復雜的人際關(guān)系。對于并不很外向的人,多數時(shí)候和自己有交集的朋友交往就可以了。我們看下代碼:有如下場(chǎng)景,現在你和你的朋友想要玩一個(gè)活動(dòng),也許是斗地主等游戲,這個(gè)時(shí)候需要再喊一個(gè)人,于是你讓你的朋友幫你再叫一個(gè)人,有代碼如下

// 我的直接朋友
public class MyFriend {
    // 找他的朋友
    public void findHisFriend (FriendOfMyFriend fof) {
      System.out.println("這是朋友的朋友:"+ fof.name);
    }
}

// 朋友的朋友,但不是我的朋友
public class FriendOfMyFriend {
    public String name;
    public FriendOfMyFriend(String name) {
      this.name = name;
    }
}

// 我
public class Me {
    public void findFriend (MyFriend myFriend) {
      System.out.println("我找我朋友");
      // 注意這段代碼
      FriendOfMyFriend fmf = new FriendOfMyFriend("陌生人");
      myFriend.findHisFriend(fmf);
    };
}

這時(shí)我們發(fā)現一個(gè)問(wèn)題,你和你朋友的朋友并不認識,但是他卻出現在了你的“找朋友”的動(dòng)作當中(在findFriend方法內),這個(gè)時(shí)候,我們認為這違反了迪米特原則(最少知道原則),迪米特原則我們對于對象關(guān)系的處理,要減少“無(wú)效社交”,具體原則是

  • 一個(gè)類(lèi)只和朋友類(lèi)交流,朋友類(lèi)指的是出現在成員變量、方法的輸入輸出參數中的類(lèi)
  • 一個(gè)類(lèi)不和陌生類(lèi)交流,即沒(méi)有出現在成員變量、方法的輸入輸出參數中的類(lèi)

所謂的“不交流”,就是不要在代碼里看到他們我們改造一下上面的代碼

// 我朋友
public class MyFriend {
    public void findHisFriend () {
        FriendOfMyFriend fmf = new FriendOfMyFriend("陌生人");
        System.out.println("這是朋友的朋友:"+ fmf.name);
    }
}
// 朋友的朋友,但不是我的朋友
public class FriendOfMyFriend {
    public String name;
    public FriendOfMyFriend(String name) {
        this.name = name;
    }
}

// 我
public class Me {
    public void findFriend (MyFriend myFriend) {
        System.out.println("我找我朋友");
        myFriend.findHisFriend();
    };
}

P6. 開(kāi)閉原則(open closed principle)

開(kāi)閉原則的意思是,軟件架構要:對修改封閉,對擴展開(kāi)放舉個(gè)例子比如我們現在在玩某一款喜歡的游戲,A鍵攻擊,F鍵閃現。這個(gè)時(shí)候我們想,如果游戲能額外給我定制一款“K”鍵,殘血時(shí)解鎖從而一擊OK對手完成5殺,那豈不美哉,這就好比是“對擴展開(kāi)放”。但是呢,如果游戲突然搞個(gè)活動(dòng),把閃現/攻擊/技能釋放的鍵盤(pán)通通換個(gè)位置,給你一個(gè)“雙十一的驚喜”,這恐怕就給人帶來(lái)慘痛的回憶了。所以我們希望已有的結構不要動(dòng),也不能動(dòng),要“對修改封閉”(本人不玩游戲,這些是自己查到的,如果錯誤還請指正)

總結

1.原則不是死板的而是靈活的

2.一些原則其實(shí)是存在一定的沖突的,重要的是權衡,是掌握好度

3.六大原則是23種設計模式的靈魂,六大原則指導了設計模式,設計模式體現了六大原則

以上就是JAVA初探設計模式的六大原則的詳細內容,更多關(guān)于JAVA設計模式六大原則的資料請關(guān)注腳本之家其它相關(guān)文章!

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

老司机精品视频一区二区| 久久精品无码专区免费| 国产 国语对白 露脸| 少妇无码太爽了在线播放| 白嫩少妇喷水正在播放| 影音先锋男人AV鲁色资源网|