日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

7种 Java 设计模式,你会几种?

發布時間:2024/4/14 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 7种 Java 设计模式,你会几种? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么要學習設計模式

設計模式并不是什么新的知識,它只是一種經驗的總結,所以必然是先有人這么去做了,然后才有人去總結提煉,從而變成了設計模式。

那么既然設計模式是前人總結的經驗,我們何不站在巨人的肩膀上,去體會經驗帶來的好處呢?

所以我們在學習設計模式的過程中,最重要的是掌握其中的設計思想,而設計模式最重要的思想就是解耦。我們需要將其解耦思想為自己所用,從而提升自己編碼能力,使自己的代碼更加容易維護、擴展。

軟件設計七大原則

在軟件開發過程中,為了提高系統的可維護性、可復用性、可擴展性以及靈活性,產生了七大設計原則,這些原則也會貫穿體現在設計模式中。設計模式會盡量遵循這些原則,但是也可能為了某一個側重點從而犧牲某些原則,在我們日常開發中也只能說盡量遵守,但是并不必為了遵守而遵守。

開閉原則

開閉原則:Open-Closed Principle,簡稱為?OCP。其核心是指在一個軟件實體中(如類,函數等),我們應該對擴展開放、對修改關閉,這樣就可以提高軟件系統的可復用性和可維護性。

開閉原則是面向對象設計的最基本原則,而遵守開閉原則的核心思想就是面向抽象編程。

下面我們以超市中的商品為例進行說明,請大家跟著我一起完成這個實驗。

因為我們有七大原則需要講解,有些原則之間類會同名,為了方便區分,我們以每一個原則的簡稱來新建一個目錄,比如開閉原則新建的目錄名為?ocp,然后相關的類就創建在?ocp?目錄下。

  • 新建一個商品接口?IGoods.java,接口中定義了兩個方法:一個獲取商品名,一個獲取商品出售價。
package ocp;import java.math.BigDecimal;public interface IGoods {String getName();//獲取商品名稱BigDecimal getSalePrice();//獲取商品每kg出售價格
  • 新建一個具體商品蔬菜類?Cabbage.java?來實現商品接口。
package ocp;import java.math.BigDecimal;public class Cabbage implements IGoods {@Overridepublic String getName() {//獲取商品名稱return "蔬菜";}@Overridepublic BigDecimal getSalePrice() {//獲取商品每kg出售價格return new BigDecimal("3.98");}

上面我們看到,蔬菜售價是 3.98/kg,那么這時候到了晚上,需要打折,售價要改為 1.98/kg,這時候普通的做法有三種選擇:

  • 直接修改?Cabbage?類的?getSalePrice。
  • 接口中再新增一個打折價方法。
  • 直接在?Cabbage?方法中新增一個獲取打折后價錢的方法。

這三種方法中:

  • 第一種可能影響到其它不需要打折的地方或者后面不打折了又要改回來,那么就需要反復修改源碼,不可行。

  • 第二種直接修改接口,影響就太大了,每個實現類都被迫需要改動(當然如果是 JDK 1.8 之后的版本可以選擇新增?default?方法,這樣方法二就和第三種方法等價了)。

  • 第三種方法貌似改動是最小的,但畢竟還是修改了源碼。

  • 簡而言之,這三種方法都需要修改源碼,違背了開閉原則中的對修改關閉這一條。所以如果要遵循開閉原則,那么我們的做法應該是再新建一個蔬菜打折類來實現?IGoods?商品。

    • 新建一個打折蔬菜類?DiscountCabbage.java。
    package ocp;import java.math.BigDecimal;public class DiscountCabbage implements IGoods {@Overridepublic String getName() {//獲取商品名稱return "蔬菜";}@Overridepublic BigDecimal getSalePrice() {//獲取商品每kg出售價格return new BigDecimal("1.98");} }
    • 最后讓我們新建一個測試類?TestOCP.java?來看看運行結果。
    package ocp;public class TestOCP {public static void main(String[] args) {System.out.println("蔬菜原價:" + new Cabbage().getSalePrice());//獲取蔬菜原價System.out.println("蔬菜打折價:" + new DiscountCabbage().getSalePrice());//獲取蔬菜打折價} }

    接下來需要執行?javac ocp/*.java?命令進行編譯。

    最后再執行?java ocp.TestOCP?命令運行測試類(大家一定要自己動手運行哦,只有自己實際去運行了才能更深入體會其中的思想)。

    這樣就符合開閉原則了,而且后面有其它商品需要打折或者其它活動,都可以通過新建一個類來實現,擴展非常方便。

    里氏替換原則

    里氏替換原則:Liskov Substitution Principle,簡稱為?LSP。其指的是繼承必須確保超類所擁有的性質在子類中仍然成立,也就是說如果對每一個類型為 T1 的對象 o1 都有類型為 T2 的對象 o2,使得以 T1 所定義的程序 P 在所有的對象 o1 都替換成為 o2 時,程序 P 的行為沒有發生改變。

    里氏替換原則具體可以總結為以下 4 點:

    • 子類可以實現父類的抽象方法,但是不能覆蓋父類的非抽象方法。
    • 子類中可以增加自己的特有方法。
    • 當子類方法重載父類的方法時,方法的前置條件(即方法的輸入/入參)要比父類方法輸入的參數更寬松。
    • 當子類實現父類的方法(重載/重寫/實現抽象方法),方法的后置條件(即方法的輸出/返回值)要比父類更嚴格或者相等。

    我們以動物鳥類飛翔舉例進行說明。同樣的,這里需要新建一個?lsp?目錄,相關類創建在?lsp?目錄下。

    • 新建一個鳥類?Bird.java。
    package lsp;public class Bird {public void fly() {System.out.println("我正在天上飛");} }
    • 再新建一個鷹類?Eagle.java?來繼承 Bird,并重寫其中的 fly 方法。
    package lsp;public class Eagle extends Bird {@Overridepublic void fly() {System.out.println("我正在8000米高空飛翔");} }
    • 新建一個測試類?TestLSP.java?來測試。
    package lsp;public class TestLSP {public static void main(String[] args) {Bird bird = new Bird();bird.fly();//輸出:我正在天上飛Eagle eagle = new Eagle(); //替換成子類Eagle,子類重寫了父類Bird的fly方法eagle.fly();//輸出:我正在8000米高空飛翔} }

    接下來我們需要先執行?javac lsp/*.java?命令進行編譯。然后再執行?java lsp.TestLSP?命令運行測試類(大家一定要自己動手運行哦,只有自己實際去運行了才會更能體會其中的思想)。

    可以看到上面的例子中將父類替換成子類之后,fly?方法變成了在 8000 米高空飛翔(普通鳥類達不到),這就改變了父類的行為,導致替換不成立,所以這個例子就違背了里氏替換原則。

    依賴倒置原則

    依賴倒置原則:Dependence Inversion Principle,簡稱為?DIP。其指的是在設計代碼結構時,高層模塊不應該依賴低層模塊,而是都應該依賴其抽象。抽象不應該依賴細節,細節應該依賴抽象。通過依賴倒置原則可以減少類與類之間的耦合性,提高系統的穩定性,提高代碼的可讀性和可維護性,而且能夠降低修改程序所帶來的風險。

    我們以超市出售商品舉例進行說明(同樣的,這里我們需要新建一個?dip?目錄,相關類創建在?dip?目錄下)。

    • 假設一家超市剛開張,只有青菜賣,所以我們新建一個超市類?SuperMarket.java,里面只定義一個賣蔬菜的方法。
    package dip;public class SuperMarket {public void saleCabbage(){System.out.println("我有蔬菜可以賣");} }

    這個超市類直接和蔬菜綁定了,也就是依賴了具體的商品。假如要賣其它商品就需要修改源碼,違背了開閉原則,我們應該修改超市類依賴于抽象商品,而不能直接綁定具體商品。

    • 新增一個商品接口?IGoods.java,接口中定義一個出售商品方法。
    package dip;public interface IGoods {void sale(); }
    • 再新建一個蔬菜類?Cabbage.java?實現商品接口。
    package dip;public class Cabbage implements IGoods{@Overridepublic void sale() {System.out.println("我有蔬菜可以賣");} }
    • 然后還需要編輯?SuperMarket.java?文件,將原先的超市類 SuperMarket 修改一下。
    package dip;public class SuperMarket {public void sale(IGoods goods){goods.sale();} }
    • 最后讓我們新建一個測試類?TestDIP.java?來測試結果。
    package dip;public class TestDIP {public static void main(String[] args) {SuperMarket superMarket = new SuperMarket();superMarket.sale(new Cabbage());//輸出:我有蔬菜可以賣} }

    接下來我們需要先執行?javac dip/*.java?命令進行編譯。然后再執行?java dip.TestDIP?命令運行測試類(大家一定要自己動手運行哦,只有自己實際去運行了才會更能體會其中的思想)。

    這時候如果需要新增其它商品,只需要新建一個具體商品類來實現?IGoods?接口,并作為參數傳入?sale?方法就可以了。

    單一職責原則

    單一職責原則:Single Responsibility Principle,簡稱為?SRP。其指的是不要存在多于一個導致類變更的原因。假如我們有一個類里面有兩個職責,一旦其中一個職責發生需求變更,那我們修改其中一個職責就有可能導致另一個職責出現問題,在這種情況應該把兩個職責放在兩個 Class 對象之中。

    單一職責可以降低類的復雜度,提高類的可讀性和系統的可維護性,也降低了變更職責引發的風險。

    我們以超市的進貨和出售舉例進行說明(同樣的,這里我們需要新建一個?srp?目錄,相關類創建在?srp?目錄下)。

    • 新建一個商品類?Goods.java。
    package srp;public class Goods {public void action(String type){if ("進貨".equals(type)){System.out.println("我要去進貨了");}else if("售賣".equals(type)){System.out.println("我要賣商品");}} }

    這個方法里面有兩個分支:進貨和售賣。也就是一個方法里面有兩個功能(職責),假如業務邏輯非常復雜,那么一個功能發生變化需要修改有很大的風險導致另一個功能也發生異常。所以為了符合單一職責原則我們應該進行如下改寫,將這兩個職責拆分成兩個類。

    • 商品進貨類?BuyGoods.java。
    package srp;public class BuyGoods {public void action(){System.out.println("我要去進貨了");} }
    • 商品售賣類?SaleGoods.java。
    package srp;public class SaleGoods {public void action(){System.out.println("我要賣商品");} }
    • 最后我們寫一個測試類?TestSRP.java?來對比一下兩種寫法。
    package srp;public class TestSRP {public static void main(String[] args) {//不符合單一職責寫法Goods goods = new Goods();goods.action("進貨");//輸出:我要去進貨了goods.action("售賣");//輸出:我要賣商品//符合單一職責寫法BuyGoods buyGoods = new BuyGoods();buyGoods.action();//輸出:我要去進貨了SaleGoods saleGoods = new SaleGoods();saleGoods.action();//輸出:我要賣商品} }

    接下來我們需要先執行?javac srp/*.java?命令進行編譯。然后再執行?java srp.TestSRP?命令運行測試類(大家一定要自己動手運行哦,只有自己實際去運行了才會更能體會其中的思想)。

    這樣對比之后大家應該一目了然,單一職責原則的兩個行為是兩個獨立的類,修改其中一個功能,就絕對不會導致另一個功能出現異常,符合了單一職責原則。

    接口隔離原則

    接口隔離原則:Interface Segregation Principle,簡稱為?ISP。接口隔離原則符合我們所說的高內聚低耦合的設計思想,從而使得類具有很好的可讀性、可擴展性和可維護性,在設計接口的時候應該注意以下三點:

    • 一個類對其它類的依賴應建立在最小的接口之上。
    • 建立單一的接口,不建立龐大臃腫的接口。
    • 盡量細化接口,接口中的方法應適度。

    我們以常見的動物的行為舉例進行說明(同樣的,這里我們需要新建一個?isp?目錄,相關類創建在?isp?目錄下)。

    • 新建一個動物接口?IAnimal.java,定義三個方法:run,swim,fly。
    package isp;public interface IAnimal {void run();//地上跑void swim();//水里游void fly();//天上飛 }
    • 新建一個 Dog 類?Dog.java?來實現 IAnimal 接口。
    package isp;public class Dog implements IAnimal {@Overridepublic void run() {System.out.println("我跑的很快");}@Overridepublic void swim() {System.out.println("我還會游泳");}@Overridepublic void fly() {} }

    可以看到,fly 方法我什么也沒做,因為狗不會飛,但是因為 fly 方法和其它方法定義在了同一個接口里面,所以使得狗具備了不該具有的行為,這就屬于接口沒有隔離,我們應該把不同特征的行為進行隔離,即拆分成不同的接口。

    • 新建一個接口?IFlyAnimal.java,只定義一個 fly 方法。
    package isp;public interface IFlyAnimal {void fly(); }
    • 新建一個接口?IRunAnimal.java,只定義一個 run 方法。
    package isp;public interface IRunAnimal {void run(); }
    • 新建一個接口?ISwimAnimal.java,只定義一個 swim 方法。
    package isp;public interface ISwimAnimal {void swim(); }
    • 然后對上面的 Dog 類?Dog.java?進行改寫。
    package isp;public class Dog implements IRunAnimal,ISwimAnimal {@Overridepublic void run() {System.out.println("我跑的很快");}@Overridepublic void swim() {System.out.println("我還會游泳");} }
    • 最后我們新建一個測試類?TestISP.java?來看一下運行效果。
    package isp;public class TestISP {public static void main(String[] args) {Dog dog = new Dog();dog.run();//狗會跑dog.swim();//狗會游泳} }

    接下來我們需要先執行?javac isp/*.java?命令進行編譯。然后再執行?java isp.TestISP?命令運行測試類(大家一定要自己動手運行哦,只有自己實際去運行了才會更能體會其中的思想)。

    這時候 Dog 需要什么行為就實現什么行為,不會再具有自己不該有的行為 fly 了。

    迪米特法則(最少知道原則)

    迪米特法則:Law of Demeter,簡稱為?LoD,又叫作最少知道原則(Least Knowledge Principle,LKP)。是指一個對象對其它對象應該保持最少的了解,盡量降低類與類之間的耦合。

    我們以超市售賣青菜,老板和經理想知道賣出去了多少斤舉例進行說明(同樣的,這里我們需要新建一個?lod?目錄,相關類創建在?lod?目錄下)。

    • 新建一個蔬菜商品類?Cabbage.java。
    package lod;public class Cabbage {public void getName(){//獲取商品名System.out.println("蔬菜");}public void saleRecord(){//獲取蔬菜售賣記錄System.out.println("蔬菜今天賣出去了100斤");} }

    這時候經理和老板都需要知道商品出售情況,那么是不是經理和老板都需要直接和商品打交道呢?實際上不需要,按常理老板只需要向經理詢問就可以了,而經理直接和商品打交道就行了。

    • 新建一個經理類?Manager.java。
    package lod;public class Manager {private Cabbage cabbage;public Manager(Cabbage cabbage) {this.cabbage = cabbage;}public void getCabbageSaleMoney(){cabbage.saleRecord();} }

    可以看到經理類里面集成了具體的商品,然后調用了商品的方法獲得商品的出售記錄。

    • 新建老板類?Boss.java。
    package lod;public class Boss {public void getCabbageSaleRecord(Manager manager){manager.getCabbageSaleMoney();} }
    • 新建一個測試類?TestLoD.java?來看看運行結果。
    package lod;public class TestLoD {public static void main(String[] args) {Boss boss = new Boss();//構建Boss實例Manager manager = new Manager(new Cabbage());//構建經理實例,經理需要和商品打交道//這里老板只需要和經理打交道就行了boss.getCabbageSaleRecord(manager);//獲得蔬菜售賣機記錄} }

    接下來我們需要先執行?javac lod/*.java?命令進行編譯。然后再執行?java lod.TestLoD?命令運行測試類(大家一定要自己動手運行哦,只有自己實際去運行了才會更能體會其中的思想)。

    上面 Boss 類不會直接和商品打交道,而是通過經理去獲取想要的接口,這就是迪米特法則。不該知道的不要知道,我只要讓該知道的人知道就好了,你想知道那你就去找那個該知道的人。后面我們要介紹的中介者模式就是一種典型的遵守了迪米特法則的設計模式。

    合成復用原則

    合成復用原則:Composite Reuse Principle,簡稱為?CRP,又叫組合/聚合復用原則(Composition/Aggregate Reuse Principle,CARP)。指的是在軟件復用時,要盡量先使用組合(has-a)或者聚合(contains-a)等關聯關系來實現,這樣可以使系統更加靈活,降低類與類之間的耦合度,一個類的變化對其它類造成的影響相對較少。

    繼承通常也稱之為白箱復用,相當于把所有的實現細節都暴露給子類。組合/聚合也稱之為黑箱復用,對類以外的對象是無法獲取到實現細節的。

    這個原則還是非常好理解的,像我們開發中經常用的依賴注入,其實就是組合,還有上面的迪米特法則中的經理類就是組合了商品類,所以在這里就不再單獨舉例子了。

    寫在最后

    設計模式是一種思想,而軟件設計七大原則就是設計思想的基石,設計模式之中可以處處看到這些設計原則,所以想要學好設計模式,那么這軟件設計的七大原則還是需要好好體會并理解,只有這樣,后面學習設計模式才會知其然更知其所以然。

    點擊《Java 設計模式系統精講》進入學習頁面。

    總結

    以上是生活随笔為你收集整理的7种 Java 设计模式,你会几种?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 午夜在线视频免费 | 欧美成人国产 | 国产精品色 | sese久久 | 久中文字幕 | 色老头一区 | 黄色一区二区三区 | 超碰毛片 | 欧美成人一区二区三区四区 | 亚洲天天综合 | 久久久精品中文字幕麻豆发布 | 国产精品69毛片高清亚洲 | 日韩av动漫 | 可以免费看av的网站 | 50度灰在线| 国产爆乳无码一区二区麻豆 | 久久国内视频 | 亚洲狼人干 | 亚洲第一在线播放 | 一区二区免费在线观看视频 | 免费福利视频在线观看 | 久久av无码精品人妻出轨 | 国产综合精品视频 | 韩国视频一区 | 99热青青草 | 午夜不卡av | 亚洲一区二区三区无码久久 | 催眠调教后宫乱淫校园 | 污网在线看 | 粗大的内捧猛烈进出在线视频 | 国产亚洲精品久久久久久久久动漫 | 宅男午夜影院 | 国产一国产二国产三 | 黄色av影视 | 国产农村妇女精品一区二区 | 91精品人妻互换一区二区 | 少妇激情偷人三级 | 久热最新视频 | 久久午夜鲁丝片午夜精品 | 成人欧美一区二区三区在线观看 | 噜噜噜久久 | 五月色丁香 | 国产91精品久久久久久久 | 波多野结衣理论片 | 亚州久久久| 深爱开心激情 | 男插女动态图 | 国内老熟妇对白xxxxhd | 欧洲熟妇的性久久久久久 | 日本三级午夜理伦三级三 | 国产91av在线播放 | 毛片av在线 | 日本69式三人交 | 深夜福利国产 | 香蕉视频免费看 | 鸭子av | 久久久久久久久久免费视频 | 深夜网站在线观看 | 国产成人精品国内自产拍免费看 | 91精品久久久久久久久中文字幕 | 国产黄a三级三级三级看三级男男 | 亚洲成人7777 | 国产黄色免费视频 | 看av免费毛片手机播放 | 国产精品高潮呻吟久久aⅴ码 | 91成人免费视频 | 黄色小视频网 | 青青成人| 亚洲成人a√ | 欧美七区| 欧美日韩国产免费观看 | 毛片大全在线观看 | 精品人妻少妇嫩草av无码 | 在线中文字日产幕 | 免费成人美女在线观看 | 曰批又黄又爽免费视频 | 久久久成人精品一区二区三区 | 福利视频免费观看 | 国产黄色免费观看 | 狠狠干很很操 | 国产3p精品一区 | 啊v视频在线观看 | 在线观看你懂的网址 | 日韩 国产 在线 | 天天操天天操天天操天天 | 亚洲国产福利视频 | 亚洲午夜激情视频 | 色人阁av| 亚洲综合中文 | 亚洲av综合色区无码另类小说 | 亚欧在线观看 | 中文字幕在线免费观看 | 婷婷综合视频 | a国产免费| 岛国精品一区 | 国产无精乱码一区二区三区 | 国产首页| 国产主播一区二区 | av网站在线播放 |