<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### 什么是設計模式 * 設計模式,是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性、程序的重用性。 ### 為什么要學習設計模式 * 看懂源代碼:如果你不懂設計模式去看Jdk、Spring、SpringMVC、IO等等等等的源碼,你會很迷茫,你會寸步難行 * 看看前輩的代碼:你去個公司難道都是新項目讓你接手?很有可能是接盤的,前輩的開發難道不用設計模式? * 編寫自己的理想中的好代碼:我個人反正是這樣的,對于我自己開發的項目我會很認真,我對他比對我女朋友還好,把項目當成自己的兒子一樣 ### 設計模式分類 ![](http://h.yiniuedu.com/540b5f24d62ec458500c7454c793cafa) * 創建型模式,共五種:**工廠方法模式、抽象工廠模式**、**單例模式**、建造者模式、**原型模式。** * 結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。 * 行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。 ### 設計模式的六大原則 ![](http://h.yiniuedu.com/87d9ba6ebe32898dbcd4e26731b65aa8) #### 開放封閉原則(Open Close Principle) * 原則思想:盡量通過擴展軟件實體來解決需求變化,而不是通過修改已有的代碼來完成變化 * 描述:一個軟件產品在生命周期內,都會發生變化,既然變化是一個既定的事實,我們就應該在設計的時候盡量適應這些變化,以提高項目的穩定性和靈活性。 * 優點:單一原則告訴我們,每個類都有自己負責的職責,里氏替換原則不能破壞繼承關系的體系。 #### 里氏代換原則(Liskov Substitution Principle) * 原則思想:使用的基類可以在任何地方使用繼承的子類,完美的替換基類。 * 大概意思是:子類可以擴展父類的功能,但不能改變父類原有的功能。子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法,子類中可以增加自己特有的方法。 * 優點:增加程序的健壯性,即使增加了子類,原有的子類還可以繼續運行,互不影響。 #### 依賴倒轉原則(Dependence Inversion Principle) * 依賴倒置原則的核心思想是面向接口編程. * 依賴倒轉原則要求我們在程序代碼中傳遞參數時或在關聯關系中,盡量引用層次高的抽象層類, * 這個是開放封閉原則的基礎,具體內容是:對接口編程,依賴于抽象而不依賴于具體。 #### 接口隔離原則(Interface Segregation Principle) * 這個原則的意思是:使用多個隔離的接口,比使用單個接口要好。還是一個降低類之間的耦合度的意思,從這兒我們看出,其實設計模式就是一個軟件的設計思想,從大型軟件架構出發,為了升級和維護方便。所以上文中多次出現:降低依賴,降低耦合。 * 例如:支付類的接口和訂單類的接口,需要把這倆個類別的接口變成倆個隔離的接口 #### 迪米特法則(最少知道原則)(Demeter Principle) * 原則思想:一個對象應當對其他對象有盡可能少地了解,簡稱類間解耦 * 大概意思就是一個類盡量減少自己對其他對象的依賴,原則是低耦合,高內聚,只有使各個模塊之間的耦合盡量的低,才能提高代碼的復用率。 * 優點:低耦合,高內聚。 #### 單一職責原則(Principle of single responsibility) * 原則思想:一個方法只負責一件事情。 * 描述:單一職責原則很簡單,一個方法 一個類只負責一個職責,各個職責的程序改動,不影響其它程序。 這是常識,幾乎所有程序員都會遵循這個原則。 * 優點:降低類和類的耦合,提高可讀性,增加可維護性和可拓展性,降低可變性的風險。 ## 單例模式 ### 1.什么是單例 * 保證一個類只有一個實例,并且提供一個訪問該全局訪問點 ### 2.那些地方用到了單例模式 1. 網站的計數器,一般也是采用單例模式實現,否則難以同步。 2. 應用程序的日志應用,一般都是單例模式實現,只有一個實例去操作才好,否則內容不好追加顯示。 3. 多線程的線程池的設計一般也是采用單例模式,因為線程池要方便對池中的線程進行控制 4. Windows的(任務管理器)就是很典型的單例模式,他不能打開倆個 5. windows的(回收站)也是典型的單例應用。在整個系統運行過程中,回收站只維護一個實例。 ### 3.單例優缺點 **優點:** 1. 在單例模式中,活動的單例只有一個實例,對單例類的所有實例化得到的都是相同的一個實例。這樣就防止其它對象對自己的實例化,確保所有的對象都訪問一個實例 2. 單例模式具有一定的伸縮性,類自己來控制實例化進程,類就在改變實例化進程上有相應的伸縮性。 3. 提供了對唯一實例的受控訪問。 4. 由于在系統內存中只存在一個對象,因此可以節約系統資源,當需要頻繁創建和銷毀的對象時單例模式無疑可以提高系統的性能。 5. 允許可變數目的實例。 6. 避免對共享資源的多重占用。 **缺點:** 1. 不適用于變化的對象,如果同一類型的對象總是要在不同的用例場景發生變化,單例就會引起數據的錯誤,不能保存彼此的狀態。 2. 由于單利模式中沒有抽象層,因此單例類的擴展有很大的困難。 3. 單例類的職責過重,在一定程度上違背了“單一職責原則”。 4. 濫用單例將帶來一些負面問題,如為了節省資源將數據庫連接池對象設計為的單例類,可能會導致共享連接池對象的程序過多而出現連接池溢出;如果實例化的對象長時間不被利用,系統會認為是垃圾而被回收,這將導致對象狀態的丟失。 ### 4.單例模式使用注意事項: 1. 使用時不能用反射模式創建單例,否則會實例化一個新的對象 2. 使用懶單例模式時注意線程安全問題 3. 餓單例模式和懶單例模式構造方法都是私有的,因而是不能被繼承的,有些單例模式可以被繼承(如登記式模式) ### 5.單例防止反射漏洞攻擊 ~~~ private static boolean flag = false; private Singleton() { if (flag == false) { flag = !flag; } else { throw new RuntimeException("單例模式被侵犯!"); } } public static void main(String[] args) { } 復制代碼 ~~~ ### 6.如何選擇單例創建方式 * 如果不需要延遲加載單例,可以使用枚舉或者餓漢式,相對來說枚舉性好于餓漢式。 如果需要延遲加載,可以使用靜態內部類或者懶漢式,相對來說靜態內部類好于懶韓式。 最好使用餓漢式 ### 7.單例創建方式 **(主要使用懶漢和懶漢式)** 1. 餓漢式:類初始化時,會立即加載該對象,線程天生安全,調用效率高。 2. 懶漢式: 類初始化時,不會初始化該對象,真正需要使用的時候才會創建該對象,具備懶加載功能。 3. 靜態內部方式:結合了懶漢式和餓漢式各自的優點,真正需要對象的時候才會加載,加載類是線程安全的。 4. 枚舉單例: 使用枚舉實現單例模式 優點:實現簡單、調用效率高,枚舉本身就是單例,由jvm從根本上提供保障!避免通過反射和反序列化的漏洞, 缺點沒有延遲加載。 5. 雙重檢測鎖方式 (因為JVM本質重排序的原因,可能會初始化多次,不推薦使用) #### 1.餓漢式 1. 餓漢式:類初始化時,會立即加載該對象,線程天生安全,調用效率高。 ~~~ package com.lijie; //餓漢式 public class Demo1 { // 類初始化時,會立即加載該對象,線程安全,調用效率高 private static Demo1 demo1 = new Demo1(); private Demo1() { System.out.println("私有Demo1構造參數初始化"); } public static Demo1 getInstance() { return demo1; } public static void main(String[] args) { Demo1 s1 = Demo1.getInstance(); Demo1 s2 = Demo1.getInstance(); System.out.println(s1 == s2); } } 復制代碼 ~~~ #### 2.懶漢式 2. 懶漢式: 類初始化時,不會初始化該對象,真正需要使用的時候才會創建該對象,具備懶加載功能。 ~~~ package com.lijie; //懶漢式 public class Demo2 { //類初始化時,不會初始化該對象,真正需要使用的時候才會創建該對象。 private static Demo2 demo2; private Demo2() { System.out.println("私有Demo2構造參數初始化"); } public synchronized static Demo2 getInstance() { if (demo2 == null) { demo2 = new Demo2(); } return demo2; } public static void main(String[] args) { Demo2 s1 = Demo2.getInstance(); Demo2 s2 = Demo2.getInstance(); System.out.println(s1 == s2); } } 復制代碼 ~~~ #### 3.靜態內部類 3. 靜態內部方式:結合了懶漢式和餓漢式各自的優點,真正需要對象的時候才會加載,加載類是線程安全的。 ~~~ package com.lijie; // 靜態內部類方式 public class Demo3 { private Demo3() { System.out.println("私有Demo3構造參數初始化"); } public static class SingletonClassInstance { private static final Demo3 DEMO_3 = new Demo3(); } // 方法沒有同步 public static Demo3 getInstance() { return SingletonClassInstance.DEMO_3; } public static void main(String[] args) { Demo3 s1 = Demo3.getInstance(); Demo3 s2 = Demo3.getInstance(); System.out.println(s1 == s2); } } 復制代碼 ~~~ #### 4.枚舉單例式 4. 枚舉單例: 使用枚舉實現單例模式 優點:實現簡單、調用效率高,枚舉本身就是單例,由jvm從根本上提供保障!避免通過反射和反序列化的漏洞, 缺點沒有延遲加載。 ~~~ package com.lijie; //使用枚舉實現單例模式 優點:實現簡單、枚舉本身就是單例,由jvm從根本上提供保障!避免通過反射和反序列化的漏洞 缺點沒有延遲加載 public class Demo4 { public static Demo4 getInstance() { return Demo.INSTANCE.getInstance(); } public static void main(String[] args) { Demo4 s1 = Demo4.getInstance(); Demo4 s2 = Demo4.getInstance(); System.out.println(s1 == s2); } //定義枚舉 private static enum Demo { INSTANCE; // 枚舉元素為單例 private Demo4 demo4; private Demo() { System.out.println("枚舉Demo私有構造參數"); demo4 = new Demo4(); } public Demo4 getInstance() { return demo4; } } } 復制代碼 ~~~ #### 5.雙重檢測鎖方式 5. 雙重檢測鎖方式 (因為JVM本質重排序的原因,可能會初始化多次,不推薦使用) ~~~ package com.lijie; //雙重檢測鎖方式 public class Demo5 { private static Demo5 demo5; private Demo5() { System.out.println("私有Demo4構造參數初始化"); } public static Demo5 getInstance() { if (demo5 == null) { synchronized (Demo5.class) { if (demo5 == null) { demo5 = new Demo5(); } } } return demo5; } public static void main(String[] args) { Demo5 s1 = Demo5.getInstance(); Demo5 s2 = Demo5.getInstance(); System.out.println(s1 == s2); } } 復制代碼 ~~~ ## 工廠模式 ### 1.什么是工廠模式 * 它提供了一種創建對象的最佳方式。在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,并且是通過使用一個共同的接口來指向新創建的對象。實現了創建者和調用者分離,工廠模式分為簡單工廠、工廠方法、抽象工廠模式 ### 2.工廠模式好處 * 工廠模式是我們最常用的實例化對象模式了,是用工廠方法代替new操作的一種模式。 * 利用工廠模式可以降低程序的耦合性,為后期的維護修改提供了很大的便利。 * 將選擇實現類、創建對象統一管理和控制。從而將調用者跟我們的實現類解耦。 ### 3.為什么要學習工廠設計模式 * 不知道你們面試題問到過源碼沒有,你知道Spring的源碼嗎,MyBatis的源碼嗎,等等等 如果你想學習很多框架的源碼,或者你想自己開發自己的框架,就必須先掌握設計模式(工廠設計模式用的是非常非常廣泛的) ### 4.Spring開發中的工廠設計模式 **1.Spring IOC** * 看過Spring源碼就知道,在Spring IOC容器創建bean的過程是使用了工廠設計模式 * Spring中無論是通過xml配置還是通過配置類還是注解進行創建bean,大部分都是通過簡單工廠來進行創建的。 * 當容器拿到了beanName和class類型后,動態的通過反射創建具體的某個對象,最后將創建的對象放到Map中。 **2.為什么Spring IOC要使用工廠設計模式創建Bean呢** * 在實際開發中,如果我們A對象調用B,B調用C,C調用D的話我們程序的耦合性就會變高。(耦合大致分為類與類之間的依賴,方法與方法之間的依賴。) * 在很久以前的三層架構編程時,都是控制層調用業務層,業務層調用數據訪問層時,都是是直接new對象,耦合性大大提升,代碼重復量很高,對象滿天飛 * 為了避免這種情況,Spring使用工廠模式編程,寫一個工廠,由工廠創建Bean,以后我們如果要對象就直接管工廠要就可以,剩下的事情不歸我們管了。Spring IOC容器的工廠中有個靜態的Map集合,是為了讓工廠符合單例設計模式,即每個對象只生產一次,生產出對象后就存入到Map集合中,保證了實例不會重復影響程序效率。 ### 5.工廠模式分類 * 工廠模式分為簡單工廠、工廠方法、抽象工廠模式 ~~~ 簡單工廠 :用來生產同一等級結構中的任意產品。(不支持拓展增加產品) 工廠方法 :用來生產同一等級結構中的固定產品。(支持拓展增加產品) 抽象工廠 :用來生產不同產品族的全部產品。(不支持拓展增加產品;支持增加產品族) 復制代碼 ~~~ `我下面來使用代碼演示一下:` #### 5.1 簡單工廠模式 **什么是簡單工廠模式** * 簡單工廠模式相當于是一個工廠中有各種產品,創建在一個類中,客戶無需知道具體產品的名稱,只需要知道產品類所對應的參數即可。但是工廠的職責過重,而且當類型過多時不利于系統的擴展維護。 **代碼演示:** 1. 創建工廠 ~~~ package com.lijie; public interface Car { public void run(); } 復制代碼 ~~~ 2. 創建工廠的產品(寶馬) ~~~ package com.lijie; public class Bmw implements Car { public void run() { System.out.println("我是寶馬汽車..."); } } 復制代碼 ~~~ 3. 創建工另外一種產品(奧迪) ~~~ package com.lijie; public class AoDi implements Car { public void run() { System.out.println("我是奧迪汽車.."); } } 復制代碼 ~~~ 4. 創建核心工廠類,由他決定具體調用哪產品 ~~~ package com.lijie; public class CarFactory { public static Car createCar(String name) { if ("".equals(name)) { return null; } if(name.equals("奧迪")){ return new AoDi(); } if(name.equals("寶馬")){ return new Bmw(); } return null; } } 復制代碼 ~~~ 5. 演示創建工廠的具體實例 ~~~ package com.lijie; public class Client01 { public static void main(String[] args) { Car aodi =CarFactory.createCar("奧迪"); Car bmw =CarFactory.createCar("寶馬"); aodi.run(); bmw.run(); } } 復制代碼 ~~~ **單工廠的優點/缺點** * 優點:簡單工廠模式能夠根據外界給定的信息,決定究竟應該創建哪個具體類的對象。明確區分了各自的職責和權力,有利于整個軟件體系結構的優化。 * 缺點:很明顯工廠類集中了所有實例的創建邏輯,容易違反GRASPR的高內聚的責任分配原則 #### 5.2 工廠方法模式 **什么是工廠方法模式** * 工廠方法模式Factory Method,又稱多態性工廠模式。在工廠方法模式中,核心的工廠類不再負責所有的產品的創建,而是將具體創建的工作交給子類去做。該核心類成為一個抽象工廠角色,僅負責給出具體工廠子類必須實現的接口,而不接觸哪一個產品類應當被實例化這種細節 **代碼演示:** 1. 創建工廠 ~~~ package com.lijie; public interface Car { public void run(); } 復制代碼 ~~~ 2. 創建工廠方法調用接口(所有的產品需要new出來必須繼承他來實現方法) ~~~ package com.lijie; public interface CarFactory { Car createCar(); } 復制代碼 ~~~ 3. 創建工廠的產品(奧迪) ~~~ package com.lijie; public class AoDi implements Car { public void run() { System.out.println("我是奧迪汽車.."); } } 復制代碼 ~~~ 4. 創建工廠另外一種產品(寶馬) ~~~ package com.lijie; public class Bmw implements Car { public void run() { System.out.println("我是寶馬汽車..."); } } 復制代碼 ~~~ 5. 創建工廠方法調用接口的實例(奧迪) ~~~ package com.lijie; public class AoDiFactory implements CarFactory { public Car createCar() { return new AoDi(); } } 復制代碼 ~~~ 6. 創建工廠方法調用接口的實例(寶馬) ~~~ package com.lijie; public class BmwFactory implements CarFactory { public Car createCar() { return new Bmw(); } } 復制代碼 ~~~ 7. 演示創建工廠的具體實例 ~~~ package com.lijie; public class Client { public static void main(String[] args) { Car aodi = new AoDiFactory().createCar(); Car jili = new BmwFactory().createCar(); aodi.run(); jili.run(); } } 復制代碼 ~~~ #### 5.3 抽象工廠模式 **什么是抽象工廠模式** * 抽象工廠簡單地說是工廠的工廠,抽象工廠可以創建具體工廠,由具體工廠來產生具體產品。 ![](http://h.yiniuedu.com/f79508378d07ed0181d9c827ef356578) **代碼演示:** 1. 創建第一個子工廠,及實現類 ~~~ package com.lijie; //汽車 public interface Car { void run(); } class CarA implements Car{ public void run() { System.out.println("寶馬"); } } class CarB implements Car{ public void run() { System.out.println("摩拜"); } } 復制代碼 ~~~ 2. 創建第二個子工廠,及實現類 ~~~ package com.lijie; //發動機 public interface Engine { void run(); } class EngineA implements Engine { public void run() { System.out.println("轉的快!"); } } class EngineB implements Engine { public void run() { System.out.println("轉的慢!"); } } 復制代碼 ~~~ 3. 創建一個總工廠,及實現類(由總工廠的實現類決定調用那個工廠的那個實例) ~~~ package com.lijie; public interface TotalFactory { // 創建汽車 Car createChair(); // 創建發動機 Engine createEngine(); } //總工廠實現類,由他決定調用哪個工廠的那個實例 class TotalFactoryReally implements TotalFactory { public Engine createEngine() { return new EngineA(); } public Car createChair() { return new CarA(); } } 復制代碼 ~~~ 4. 運行測試 ~~~ package com.lijie; public class Test { public static void main(String[] args) { TotalFactory totalFactory2 = new TotalFactoryReally(); Car car = totalFactory2.createChair(); car.run(); TotalFactory totalFactory = new TotalFactoryReally(); Engine engine = totalFactory.createEngine(); engine.run(); } } 復制代碼 ~~~ ## 代理模式 ### 1.什么是代理模式 * 通過代理控制對象的訪問,可以在這個對象調用方法之前、調用方法之后去處理/添加新的功能。(也就是AO的P微實現) * 代理在原有代碼乃至原業務流程都不修改的情況下,直接在業務流程中切入新代碼,增加新功能,這也和Spring的(面向切面編程)很相似 ### 2.代理模式應用場景 * Spring AOP、日志打印、異常處理、事務控制、權限控制等 ### 3.代理的分類 * 靜態代理(靜態定義代理類) * 動態代理(動態生成代理類,也稱為Jdk自帶動態代理) * Cglib 、javaassist(字節碼操作庫) ### 4.三種代理的區別 1. 靜態代理:簡單代理模式,是動態代理的理論基礎。常見使用在代理模式 2. jdk動態代理:使用反射完成代理。需要有頂層接口才能使用,常見是mybatis的mapper文件是代理。 3. cglib動態代理:也是使用反射完成代理,可以直接代理類(jdk動態代理不行),使用字節碼技術,不能對 final類進行繼承。(需要導入jar包) ### 5.用代碼演示三種代理 #### 5.1.靜態代理 **什么是靜態代理** * 由程序員創建或工具生成代理類的源碼,再編譯代理類。所謂靜態也就是在程序運行前就已經存在代理類的字節碼文件,代理類和委托類的關系在運行前就確定了。 **代碼演示:** * 我有一段這樣的代碼:(如何能在不修改UserDao接口類的情況下開事務和關閉事務呢) ~~~ package com.lijie; //接口類 public class UserDao{ public void save() { System.out.println("保存數據方法"); } } 復制代碼 ~~~ ~~~ package com.lijie; //運行測試類 public class Test{ public static void main(String[] args) { UserDao userDao = new UserDao(); userDao.save(); } } 復制代碼 ~~~ **修改代碼,添加代理類** ~~~ package com.lijie; //代理類 public class UserDaoProxy extends UserDao { private UserDao userDao; public UserDaoProxy(UserDao userDao) { this.userDao = userDao; } public void save() { System.out.println("開啟事物..."); userDao.save(); System.out.println("關閉事物..."); } } 復制代碼 ~~~ ~~~ //添加完靜態代理的測試類 public class Test{ public static void main(String[] args) { UserDao userDao = new UserDao(); UserDaoProxy userDaoProxy = new UserDaoProxy(userDao); userDaoProxy.save(); } } 復制代碼 ~~~ * 缺點:每個需要代理的對象都需要自己重復編寫代理,很不舒服, * 優點:但是可以面相實際對象或者是接口的方式實現代理 #### 2.2.動態代理 **什么是動態代理** * 動態代理也叫做,JDK代理、接口代理。 * 動態代理的對象,是利用JDK的API,動態的在內存中構建代理對象(是根據被代理的接口來動態生成代理類的class文件,并加載運行的過程),這就叫動態代理 ~~~ package com.lijie; //接口 public interface UserDao { void save(); } 復制代碼 ~~~ ~~~ package com.lijie; //接口實現類 public class UserDaoImpl implements UserDao { public void save() { System.out.println("保存數據方法"); } } 復制代碼 ~~~ * //下面是代理類,可重復使用,不像靜態代理那樣要自己重復編寫代理 ~~~ package com.lijie; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; // 每次生成動態代理類對象時,實現了InvocationHandler接口的調用處理器對象 public class InvocationHandlerImpl implements InvocationHandler { // 這其實業務實現類對象,用來調用具體的業務方法 private Object target; // 通過構造函數傳入目標對象 public InvocationHandlerImpl(Object target) { this.target = target; } //動態代理實際運行的代理方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("調用開始處理"); //下面invoke()方法是以反射的方式來創建對象,第一個參數是要創建的對象,第二個是構成方法的參數,由第二個參數來決定創建對象使用哪個構造方法 Object result = method.invoke(target, args); System.out.println("調用結束處理"); return result; } } 復制代碼 ~~~ * //利用動態代理使用代理方法 ~~~ package com.lijie; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { // 被代理對象 UserDao userDaoImpl = new UserDaoImpl(); InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDaoImpl); //類加載器 ClassLoader loader = userDaoImpl.getClass().getClassLoader(); Class<?>[] interfaces = userDaoImpl.getClass().getInterfaces(); // 主要裝載器、一組接口及調用處理動態代理實例 UserDao newProxyInstance = (UserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl); newProxyInstance.save(); } } 復制代碼 ~~~ * 缺點:必須是面向接口,目標業務類必須實現接口 * 優點:不用關心代理類,只需要在運行階段才指定代理哪一個對象 #### 5.3.CGLIB動態代理 **CGLIB動態代理原理:** * 利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。 **什么是CGLIB動態代理** * CGLIB動態代理和jdk代理一樣,使用反射完成代理,不同的是他可以直接代理類(jdk動態代理不行,他必須目標業務類必須實現接口),CGLIB動態代理底層使用字節碼技術,CGLIB動態代理不能對 final類進行繼承。(CGLIB動態代理需要導入jar包) **代碼演示:** ~~~ package com.lijie; //接口 public interface UserDao { void save(); } 復制代碼 ~~~ ~~~ package com.lijie; //接口實現類 public class UserDaoImpl implements UserDao { public void save() { System.out.println("保存數據方法"); } } 復制代碼 ~~~ ~~~ package com.lijie; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; //代理主要類 public class CglibProxy implements MethodInterceptor { private Object targetObject; // 這里的目標類型為Object,則可以接受任意一種參數作為被代理類,實現了動態代理 public Object getInstance(Object target) { // 設置需要創建子類的類 this.targetObject = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } //代理實際方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("開啟事物"); Object result = proxy.invoke(targetObject, args); System.out.println("關閉事物"); // 返回代理對象 return result; } } 復制代碼 ~~~ ~~~ package com.lijie; //測試CGLIB動態代理 public class Test { public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDaoImpl()); userDao.save(); } } 復制代碼 ~~~ ## 建造者模式 ### 1.什么是建造者模式 * 建造者模式:是將一個復雜的對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的方式進行創建。 * 工廠類模式是提供的是創建單個類的產品 * 而建造者模式則是將各種產品集中起來進行管理,用來具有不同的屬性的產品 **建造者模式通常包括下面幾個角色:** 1. uilder:給出一個抽象接口,以規范產品對象的各個組成成分的建造。這個接口規定要實現復雜對象的哪些部分的創建,并不涉及具體的對象部件的創建。 2. ConcreteBuilder:實現Builder接口,針對不同的商業邏輯,具體化復雜對象的各部分的創建。 在建造過程完成后,提供產品的實例。 3. Director:調用具體建造者來創建復雜對象的各個部分,在指導者中不涉及具體產品的信息,只負責保證對象各部分完整創建或按某種順序創建。 4. Product:要創建的復雜對象。 ### 2.建造者模式的使用場景 **使用場景:** 1. 需要生成的對象具有復雜的內部結構。 2. 需要生成的對象內部屬性本身相互依賴。 * 與工廠模式的區別是:建造者模式更加關注與零件裝配的順序。 * JAVA 中的 StringBuilder就是建造者模式創建的,他把一個單個字符的char數組組合起來 * Spring不是建造者模式,它提供的操作應該是對于字符串本身的一些操作,而不是創建或改變一個字符串。 ### 3.代碼案例 1. 建立一個裝備對象Arms ~~~ package com.lijie; //裝備類 public class Arms { //頭盔 private String helmet; //鎧甲 private String armor; //武器 private String weapon; //省略Git和Set方法........... } 復制代碼 ~~~ 2. 創建Builder接口(給出一個抽象接口,以規范產品對象的各個組成成分的建造,這個接口只是規范) ~~~ package com.lijie; public interface PersonBuilder { void builderHelmetMurder(); void builderArmorMurder(); void builderWeaponMurder(); void builderHelmetYanLong(); void builderArmorYanLong(); void builderWeaponYanLong(); Arms BuilderArms(); //組裝 } 復制代碼 ~~~ 3. 創建Builder實現類(這個類主要實現復雜對象創建的哪些部分需要什么屬性) ~~~ package com.lijie; public class ArmsBuilder implements PersonBuilder { private Arms arms; //創建一個Arms實例,用于調用set方法 public ArmsBuilder() { arms = new Arms(); } public void builderHelmetMurder() { arms.setHelmet("奪命頭盔"); } public void builderArmorMurder() { arms.setArmor("奪命鎧甲"); } public void builderWeaponMurder() { arms.setWeapon("奪命寶刀"); } public void builderHelmetYanLong() { arms.setHelmet("炎龍頭盔"); } public void builderArmorYanLong() { arms.setArmor("炎龍鎧甲"); } public void builderWeaponYanLong() { arms.setWeapon("炎龍寶刀"); } public Arms BuilderArms() { return arms; } } 復制代碼 ~~~ 4. Director(調用具體建造者來創建復雜對象的各個部分,在指導者中不涉及具體產品的信息,只負責保證對象各部分完整創建或按某種順序創建) ~~~ package com.lijie; public class PersonDirector { //組裝 public Arms constructPerson(PersonBuilder pb) { pb.builderHelmetYanLong(); pb.builderArmorMurder(); pb.builderWeaponMurder(); return pb.BuilderArms(); } //這里進行測試 public static void main(String[] args) { PersonDirector pb = new PersonDirector(); Arms arms = pb.constructPerson(new ArmsBuilder()); System.out.println(arms.getHelmet()); System.out.println(arms.getArmor()); System.out.println(arms.getWeapon()); } } 復制代碼 ~~~ ## 模板方法模式 ### 1.什么是模板方法 * 模板方法模式:定義一個操作中的算法骨架(父類),而將一些步驟延遲到子類中。 模板方法使得子類可以不改變一個算法的結構來重定義該算法的 ### 2.什么時候使用模板方法 * 實現一些操作時,整體步驟很固定,但是呢。就是其中一小部分需要改變,這時候可以使用模板方法模式,將容易變的部分抽象出來,供子類實現。 ### 3.實際開發中應用場景哪里用到了模板方法 * 其實很多框架中都有用到了模板方法模式 * 例如:數據庫訪問的封裝、Junit單元測試、servlet中關于doGet/doPost方法的調用等等 ### 4.現實生活中的模板方法 **例如:** 1. 去餐廳吃飯,餐廳給我們提供了一個模板就是:看菜單,點菜,吃飯,付款,走人 (這里 “**點菜和付款**” 是不確定的由子類來完成的,其他的則是一個模板。) ### 5.代碼實現模板方法模式 1. 先定義一個模板。把模板中的點菜和付款,讓子類來實現。 ~~~ package com.lijie; //模板方法 public abstract class RestaurantTemplate { // 1.看菜單 public void menu() { System.out.println("看菜單"); } // 2.點菜業務 abstract void spotMenu(); // 3.吃飯業務 public void havingDinner(){ System.out.println("吃飯"); } // 3.付款業務 abstract void payment(); // 3.走人 public void GoR() { System.out.println("走人"); } //模板通用結構 public void process(){ menu(); spotMenu(); havingDinner(); payment(); GoR(); } } 復制代碼 ~~~ 2. 具體的模板方法子類 1 ~~~ package com.lijie; public class RestaurantGinsengImpl extends RestaurantTemplate { void spotMenu() { System.out.println("人參"); } void payment() { System.out.println("5快"); } } 復制代碼 ~~~ 3. 具體的模板方法子類 2 ~~~ package com.lijie; public class RestaurantLobsterImpl extends RestaurantTemplate { void spotMenu() { System.out.println("龍蝦"); } void payment() { System.out.println("50塊"); } } 復制代碼 ~~~ 4. 客戶端測試 ~~~ package com.lijie; public class Client { public static void main(String[] args) { //調用第一個模板實例 RestaurantTemplate restaurantTemplate = new RestaurantGinsengImpl(); restaurantTemplate.process(); } } 復制代碼 ~~~ ## 外觀模式 ### 1.什么是外觀模式 * 外觀模式:也叫門面模式,隱藏系統的復雜性,并向客戶端提供了一個客戶端可以訪問系統的接口。 * 它向現有的系統添加一個接口,用這一個接口來隱藏實際的系統的復雜性。 * 使用外觀模式,他外部看起來就是一個接口,其實他的內部有很多復雜的接口已經被實現 ### 2.外觀模式例子 * 用戶注冊完之后,需要調用阿里短信接口、郵件接口、微信推送接口。 1. 創建阿里短信接口 ~~~ package com.lijie; //阿里短信消息 public interface AliSmsService { void sendSms(); } 復制代碼 ~~~ ~~~ package com.lijie; public class AliSmsServiceImpl implements AliSmsService { public void sendSms() { System.out.println("阿里短信消息"); } } 復制代碼 ~~~ 2. 創建郵件接口 ~~~ package com.lijie; //發送郵件消息 public interface EamilSmsService { void sendSms(); } 復制代碼 ~~~ ~~~ package com.lijie; public class EamilSmsServiceImpl implements EamilSmsService{ public void sendSms() { System.out.println("發送郵件消息"); } } 復制代碼 ~~~ 3. 創建微信推送接口 ~~~ package com.lijie; //微信消息推送 public interface WeiXinSmsService { void sendSms(); } 復制代碼 ~~~ ~~~ package com.lijie; public class WeiXinSmsServiceImpl implements WeiXinSmsService { public void sendSms() { System.out.println("發送微信消息推送"); } } 復制代碼 ~~~ 4. 創建門面(門面看起來很簡單使用,復雜的東西以及被門面給封裝好了) ~~~ package com.lijie; public class Computer { AliSmsService aliSmsService; EamilSmsService eamilSmsService; WeiXinSmsService weiXinSmsService; public Computer() { aliSmsService = new AliSmsServiceImpl(); eamilSmsService = new EamilSmsServiceImpl(); weiXinSmsService = new WeiXinSmsServiceImpl(); } //只需要調用它 public void sendMsg() { aliSmsService.sendSms(); eamilSmsService.sendSms(); weiXinSmsService.sendSms(); } } 復制代碼 ~~~ 5. 啟動測試 ~~~ package com.lijie; public class Client { public static void main(String[] args) { //普通模式需要這樣 AliSmsService aliSmsService = new AliSmsServiceImpl(); EamilSmsService eamilSmsService = new EamilSmsServiceImpl(); WeiXinSmsService weiXinSmsService = new WeiXinSmsServiceImpl(); aliSmsService.sendSms(); eamilSmsService.sendSms(); weiXinSmsService.sendSms(); //利用外觀模式簡化方法 new Computer().sendMsg(); } } 復制代碼 ~~~ ## 原型模式 ### 1.什么是原型模式 * 原型設計模式簡單來說就是克隆 * 原型表明了有一個樣板實例,這個原型是可定制的。原型模式多用于創建復雜的或者構造耗時的實例,因為這種情況下,復制一個已經存在的實例可使程序運行更高效。 ### 2.原型模式的應用場景 1. 類初始化需要消化非常多的資源,這個資源包括數據、硬件資源等。這時我們就可以通過原型拷貝避免這些消耗。 2. 通過new產生的一個對象需要非常繁瑣的數據準備或者權限,這時可以使用原型模式。 3. 一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調用者使用,即保護性拷貝。 `我們Spring框架中的多例就是使用原型。` ### 3.原型模式的使用方式 1. 實現Cloneable接口。在java語言有一個Cloneable接口,它的作用只有一個,就是在運行時通知虛擬機可以安全地在實現了此接口的類上使用clone方法。在java虛擬機中,只有實現了這個接口的類才可以被拷貝,否則在運行時會拋出CloneNotSupportedException異常。 2. 重寫Object類中的clone方法。Java中,所有類的父類都是Object類,Object類中有一個clone方法,作用是返回對象的一個拷貝,但是其作用域protected類型的,一般的類無法調用,因此Prototype類需要將clone方法的作用域修改為public類型。 #### 3.1原型模式分為淺復制和深復制 1. (淺復制)只是拷貝了基本類型的數據,而引用類型數據,只是拷貝了一份引用地址。 2. (深復制)在計算機中開辟了一塊新的內存地址用于存放復制的對象。 ### 4.代碼演示 1. 創建User類 ~~~ package com.lijie; import java.util.ArrayList; public class User implements Cloneable { private String name; private String password; private ArrayList<String> phones; protected User clone() { try { User user = (User) super.clone(); //重點,如果要連帶引用類型一起復制,需要添加底下一條代碼,如果不加就對于是復制了引用地址 user.phones = (ArrayList<String>) this.phones.clone();//設置深復制 return user; } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } //省略所有屬性Git Set方法...... } 復制代碼 ~~~ 2. 測試復制 ~~~ package com.lijie; import java.util.ArrayList; public class Client { public static void main(String[] args) { //創建User原型對象 User user = new User(); user.setName("李三"); user.setPassword("123456"); ArrayList<String> phones = new ArrayList<>(); phones.add("17674553302"); user.setPhones(phones); //copy一個user對象,并且對象的屬性 User user2 = user.clone(); user2.setPassword("654321"); //查看倆個對象是否是一個 System.out.println(user == user2); //查看屬性內容 System.out.println(user.getName() + " | " + user2.getName()); System.out.println(user.getPassword() + " | " + user2.getPassword()); //查看對于引用類型拷貝 System.out.println(user.getPhones() == user2.getPhones()); } } 復制代碼 ~~~ 3. 如果不需要深復制,需要刪除User 中的 ~~~ //默認引用類型為淺復制,這是設置了深復制 user.phones = (ArrayList<String>) this.phones.clone(); 復制代碼 ~~~ ## 策略模式 ### 1.什么是策略模式 * 定義了一系列的算法 或 邏輯 或 相同意義的操作,并將每一個算法、邏輯、操作封裝起來,而且使它們還可以相互替換。(其實策略模式Java中用的非常非常廣泛) * 我覺得主要是為了 簡化 if...else 所帶來的復雜和難以維護。 ### 2.策略模式應用場景 * 策略模式的用意是針對一組算法或邏輯,將每一個算法或邏輯封裝到具有共同接口的獨立的類中,從而使得它們之間可以相互替換。 1. 例如:我要做一個不同會員打折力度不同的三種策略,初級會員,中級會員,高級會員(三種不同的計算)。 2. 例如:我要一個支付模塊,我要有微信支付、支付寶支付、銀聯支付等 ### 3.策略模式的優點和缺點 * 優點: 1、算法可以自由切換。 2、避免使用多重條件判斷。 3、擴展性非常良好。 * 缺點: 1、策略類會增多。 2、所有策略類都需要對外暴露。 ### 4.代碼演示 * 模擬支付模塊有微信支付、支付寶支付、銀聯支付 1. 定義抽象的公共方法 ~~~ package com.lijie; //策略模式 定義抽象方法 所有支持公共接口 abstract class PayStrategy { // 支付邏輯方法 abstract void algorithmInterface(); } 復制代碼 ~~~ 2. 定義實現微信支付 ~~~ package com.lijie; class PayStrategyA extends PayStrategy { void algorithmInterface() { System.out.println("微信支付"); } } 復制代碼 ~~~ 3. 定義實現支付寶支付 ~~~ package com.lijie; class PayStrategyB extends PayStrategy { void algorithmInterface() { System.out.println("支付寶支付"); } } 復制代碼 ~~~ 4. 定義實現銀聯支付 ~~~ package com.lijie; class PayStrategyC extends PayStrategy { void algorithmInterface() { System.out.println("銀聯支付"); } } 復制代碼 ~~~ 5. 定義下文維護算法策略 ~~~ package com.lijie;// 使用上下文維護算法策略 class Context { PayStrategy strategy; public Context(PayStrategy strategy) { this.strategy = strategy; } public void algorithmInterface() { strategy.algorithmInterface(); } } 復制代碼 ~~~ 6. 運行測試 ~~~ package com.lijie; class ClientTestStrategy { public static void main(String[] args) { Context context; //使用支付邏輯A context = new Context(new PayStrategyA()); context.algorithmInterface(); //使用支付邏輯B context = new Context(new PayStrategyB()); context.algorithmInterface(); //使用支付邏輯C context = new Context(new PayStrategyC()); context.algorithmInterface(); } } 復制代碼 ~~~ ## 觀察者模式 ### 1.什么是觀察者模式 * 先講什么是行為性模型,行為型模式關注的是系統中對象之間的相互交互,解決系統在運行時對象之間的相互通信和協作,進一步明確對象的職責。 * 觀察者模式,是一種行為性模型,又叫發布-訂閱模式,他定義對象之間一種一對多的依賴關系,使得當一個對象改變狀態,則所有依賴于它的對象都會得到通知并自動更新。 ### 2.模式的職責 * 觀察者模式主要用于1對N的通知。當一個對象的狀態變化時,他需要及時告知一系列對象,令他們做出相應。 **實現有兩種方式:** 1. 推:每次都會把通知以廣播的方式發送給所有觀察者,所有的觀察者只能被動接收。 2. 拉:觀察者只要知道有情況即可,至于什么時候獲取內容,獲取什么內容,都可以自主決定。 ### 3.觀察者模式應用場景 1. 關聯行為場景,需要注意的是,關聯行為是可拆分的,而不是“組合”關系。事件多級觸發場景。 2. 跨系統的消息交換場景,如消息隊列、事件總線的處理機制。 ### 4.代碼實現觀察者模式 1. 定義抽象觀察者,每一個實現該接口的實現類都是具體觀察者。 ~~~ package com.lijie; //觀察者的接口,用來存放觀察者共有方法 public interface Observer { // 觀察者方法 void update(int state); } 復制代碼 ~~~ 2. 定義具體觀察者 ~~~ package com.lijie; // 具體觀察者 public class ObserverImpl implements Observer { // 具體觀察者的屬性 private int myState; public void update(int state) { myState=state; System.out.println("收到消息,myState值改為:"+state); } public int getMyState() { return myState; } } 復制代碼 ~~~ 3. 定義主題。主題定義觀察者數組,并實現增、刪及通知操作。 ~~~ package com.lijie; import java.util.Vector; //定義主題,以及定義觀察者數組,并實現增、刪及通知操作。 public class Subjecct { //觀察者的存儲集合,不推薦ArrayList,線程不安全, private Vector<Observer> list = new Vector<>(); // 注冊觀察者方法 public void registerObserver(Observer obs) { list.add(obs); } // 刪除觀察者方法 public void removeObserver(Observer obs) { list.remove(obs); } // 通知所有的觀察者更新 public void notifyAllObserver(int state) { for (Observer observer : list) { observer.update(state); } } } 復制代碼 ~~~ 4. 定義具體的,他繼承繼承Subject類,在這里實現具體業務,在具體項目中,該類會有很多。 ~~~ package com.lijie; //具體主題 public class RealObserver extends Subjecct { //被觀察對象的屬性 private int state; public int getState(){ return state; } public void setState(int state){ this.state=state; //主題對象(目標對象)值發生改變 this.notifyAllObserver(state); } } 復制代碼 ~~~ 5. 運行測試 ~~~ package com.lijie; public class Client { public static void main(String[] args) { // 目標對象 RealObserver subject = new RealObserver(); // 創建多個觀察者 ObserverImpl obs1 = new ObserverImpl(); ObserverImpl obs2 = new ObserverImpl(); ObserverImpl obs3 = new ObserverImpl(); // 注冊到觀察隊列中 subject.registerObserver(obs1); subject.registerObserver(obs2); subject.registerObserver(obs3); // 改變State狀態 subject.setState(300); System.out.println("obs1觀察者的MyState狀態值為:"+obs1.getMyState()); System.out.println("obs2觀察者的MyState狀態值為:"+obs2.getMyState()); System.out.println("obs3觀察者的MyState狀態值為:"+obs3.getMyState()); // 改變State狀態 subject.setState(400); System.out.println("obs1觀察者的MyState狀態值為:"+obs1.getMyState()); System.out.println("obs2觀察者的MyState狀態值為:"+obs2.getMyState()); System.out.println("obs3觀察者的MyState狀態值為:"+obs3.getMyState()); } } 復制代碼 ~~~ ## 文章就到這了,沒錯,沒了 察者方法 public void removeObserver(Observer obs) { list.remove(obs); } ~~~ // 通知所有的觀察者更新 public void notifyAllObserver(int state) { for (Observer observer : list) { observer.update(state); } } 復制代碼 ~~~ } ~~~ 4. 定義具體的,他繼承繼承Subject類,在這里實現具體業務,在具體項目中,該類會有很多。 ```java package com.lijie; //具體主題 public class RealObserver extends Subjecct { //被觀察對象的屬性 private int state; public int getState(){ return state; } public void setState(int state){ this.state=state; //主題對象(目標對象)值發生改變 this.notifyAllObserver(state); } } 復制代碼 ~~~ 5. 運行測試 ~~~ package com.lijie; public class Client { public static void main(String[] args) { // 目標對象 RealObserver subject = new RealObserver(); // 創建多個觀察者 ObserverImpl obs1 = new ObserverImpl(); ObserverImpl obs2 = new ObserverImpl(); ObserverImpl obs3 = new ObserverImpl(); // 注冊到觀察隊列中 subject.registerObserver(obs1); subject.registerObserver(obs2); subject.registerObserver(obs3); // 改變State狀態 subject.setState(300); System.out.println("obs1觀察者的MyState狀態值為:"+obs1.getMyState()); System.out.println("obs2觀察者的MyState狀態值為:"+obs2.getMyState()); System.out.println("obs3觀察者的MyState狀態值為:"+obs3.getMyState()); // 改變State狀態 subject.setState(400); System.out.println("obs1觀察者的MyState狀態值為:"+obs1.getMyState()); System.out.println("obs2觀察者的MyState狀態值為:"+obs2.getMyState()); System.out.println("obs3觀察者的MyState狀態值為:"+obs3.getMyState()); } } 復制代碼 ~~~ ## 文章就到這了,沒錯,沒了 如果不是必要,準備上面那九個設計模式就好了,全部記住有點難
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看