結構型模式之代理模式

一:設計模式

  1. 概念:設計模式(Design Pattern)是一套被反覆使用、多數人知曉的、經過分類的、代碼設計經驗的總結。
  2. 目的:爲了代碼可重用性,讓代碼更容易被他人理解、保證代碼可靠性。設計模式使代碼編寫真正工程化;設計模式是軟件工程的基石脈絡,如同大廈的結構一樣。

二:設計原則

設計模式就是因爲實現了設計原則(面向對象),從而達到了代碼複用,增加可維護性的目的。

  1. 開閉原則(Open Close Principle)
    對擴展開發,對修改關閉
    在程序需要進行擴展的時候,不能去修改原有的代碼
  2. 里氏替換原則(Liskov Substitution Principle)
    任何基類可以出現的地方,子類一定可以出現

里氏替換原則是對開閉原則的補充。實現開閉原則的關鍵步驟就是抽象化。而基類於子類的繼承關係就是抽象化的具體實現。

  1. 依賴倒置原則(Dependence Inversion Principle)
    面向接口編程,依賴於抽象/接口,而不依賴於具體實現

這個是開閉原則的基礎

  1. 接口隔離原則(Interface Segregation Principle)
    使用多個接口比使用單一接口要好,降低代碼的耦合度
  2. 迪米特法則(最少知道原則)(Demeter Principle)
    一個實體應當儘量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立。
  3. 單一職責原則(Single Responsibility Principle)
    一個類只做一件事

三:設計模式的分類

總體來說設計模式分爲三大類

  1. 創建型模式,共五種:單例模式、工廠模式、抽象工廠模式、建造者模式、原型模式。
  2. 結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
  3. 行爲模式,共十一鍾:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問模式、中介者模式、解釋器模式。

本章重點-----結構型模式之代理模式

1. 定義:

代理模式(Proxy Pattern):爲其他對象提供一種代理以控制對這個對象的訪問。
類圖:
在這裏插入圖片描述

RealSubject 具體主題角色
是業務邏輯的具體執行者
ProxySubject代理主題角色
它負者對真實角色的應用,把所有抽象主題類定義的方法限制委託給真實主題角色實現,並且在真實主題角色處理完畢前後做預處理和善後處理工作

2. 示例:

我們以找中介買二手車爲例
在這裏插入圖片描述

1. 靜態代理:

/**
 * 主要業務
 * @author xiyang.ycj
 * @since Nov 21, 2019 18:03:23 PM
 */
public interface IBuyer {
    void buy();
}
-----------------------------------
/**
 * 客戶
 * @author xiyang.ycj
 * @since Nov 21, 2019 17:59:01 PM
 */
public class Buyer implements IBuyer{

    @Override
    public void buy(){
        System.out.println("我要買輛車");
    }
}
-----------------------------------
/**
 * 中介
 * @author xiyang.ycj
 * @since Nov 21, 2019 18:01:09 PM
 */
public class ProxyBuyer implements IBuyer{

    private Buyer buyer;

    public ProxyBuyer(Buyer buyer) {
        this.buyer = buyer;
    }

    @Override
    public void buy() {
        System.out.println("中介--買車記錄---找到車源");
        buyer.buy();
        System.out.println("中介--買車記錄---交易完成--記錄業績");
    }
}
-----------------------------------
public class ProxyClient {

    @Test
    public void staticProxy(){
        // 創建一個買家
        Buyer buyer = new Buyer();
        // 找到一箇中介
        ProxyBuyer proxyBuyer = new ProxyBuyer(buyer);
        proxyBuyer.buy();
    }
}
-----------------------------------
中介--買車記錄---找到車源
我要買輛車
中介--買車記錄---交易完成--記錄業績

靜態代理:
優點:可以做到在符合開閉原則的情況下對目標進行功能擴展
缺點:我們得爲每一個服務都創建代理類,工作量太大,且一但主要業務發生改變,代理類也得改變

2. JDK動態代理:

/**
 * 動態處理器
 * @author xiyang.ycj
 * @since Nov 21, 2019 18:01:09 PM
 */
public class Dynamic implements InvocationHandler {
    private Object target;
    public Dynamic(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("中介--買車記錄---找到車源");
        Object invoke = method.invoke(this.target, args);
        System.out.println("中介--買車記錄---交易完成--記錄業績");
        return invoke;
    }
}
-----------------------------------
public class ProxyClient {

    @Test
    public void dynamicProxy(){
        // 創建一個買家
        IBuyer buyer = new Buyer();
        // 找到一箇中介
        IBuyer instance = (IBuyer)Proxy.newProxyInstance(Buyer.class.getClassLoader(), new Class[]{IBuyer.class}, new Dynamic(buyer));
        instance.buy();
    }
}
-----------------------------------
中介--買車記錄---找到車源
我要買輛車
中介--買車記錄---交易完成--記錄業績

注意Proxy.newProxyInstance()方法接收三個參數:
 ● ClassLoder loder:指定當前目標對象使用得類加載器,獲取加載器得方法是固定得。
 ● Class<?>[] interfaces:指定目標對象實現得接口的類型,使用泛型方式確認類型。
 ● InvocationHandler handler:指定動態處理器,執行目標對象的方法時,會觸發事件處理器的方法。

3. CGLIB動態代理:

由於JDK實現動態代理需要實現類通過接口定義業務方法,對於沒有接口的類,就需要CGLIB了.

CGLIB:採用非常底層的字節碼技術,其原理是通過字節碼技術爲一個類創建子類,並在子類中採用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。但不能對final修飾的類進行代理(繼承)。

/**
 * cglib方法攔截
 * @author xiyang.ycj
 * @since Nov 21, 2019 18:54:48 PM
 */
public class Cglib implements MethodInterceptor {
    /* 創建一個子類 */
    public <T> T getInstance(Class<T> clazz){
        return (T) Enhancer.create(clazz,this);
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("中介--買車記錄---找到車源");
        Object invokeSuper = methodProxy.invokeSuper(o, objects);// 調用業務類(父類中)的方法
        System.out.println("中介--買車記錄---交易完成--記錄業績");
        return invokeSuper;
    }
}
-----------------------------------
public class ProxyClient {

    @Test
    public void cglibProxy(){
        Buyer instance = new Cglib().getInstance(Buyer.class);
        instance.buy();
    }
}
-----------------------------------
中介--買車記錄---找到車源
我要買輛車
中介--買車記錄---交易完成--記錄業績

CGLIB創建的動態代理對象比JDK創建的動態代理對象的性能更高,但是CGLIB創建代理對象時所花費的時間卻比JDK多得多。所以對於單例的對象,因爲無需頻繁創建對象,用CGLIB合適,反之使用JDK方式要更爲合適一些。

3.工廠模式的應用

1. 優點:

  • 職責清晰。
    真實的角色就是實現實際的業務邏輯,不用關心其他非本職責的事務,通過後期的代理完成一件事務,附帶的結果就是編程簡潔清晰。
  • 高擴展性
  • 智能化

2. 使用場景

  • spring aop
  • 權限管理
  • 事務

四:代碼地址

代碼地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章