Java設計模式之代理模式(Proxy)


前言:

      最近在研究Retrofit開源框架的時候,其主要核心代碼是通過注解標示參數,動態代理模式實現具體接口,反射機制進行參數解析,最終實現發送請求。其實之前在學習Xutils源碼的時候,Xutils 的task也是通過代理模式來訪問的。為何要采用代理模式呢?有什么好處呢?抱着這些疑問!今天來學習總結一下。

 什么是代理模式?

       代理模式的定義:代理模式給某一個對象提供一個代理對象,並由代理對象控制對原對象的引用。舉例說明,就是一個人或者一個機構代表另一個人或者另一個機構采取行動。在一些情況下,一個客戶不想或者不能夠直接引用一個對象,而代理對象可以在客戶端和目標對象之前起到中介的作用。

應用場景舉例:

       通過上面的代理模式描述我們可以知道,其目的就是為了控制對象引用,生活場景中我們以買車為例,如果我們要買一輛轎車必須通過汽車4S店,汽車4s店就是充當代理角色,其目的就是控制買車客戶的買車行為,必須通過汽車4S店才能從汽車廠商買一輛車。

1.)首先新建一個買車的接口

public interface IBuyCar {
    //買車
    void buyCar();
}

2.)聲明一個要買車的客戶,實現買車接口

public class Customer implements IBuyCar {

    private int cash;//購車款

    public int getCash() {
        return cash;
    }

    public void setCash(int cash) {
        this.cash = cash;
    }

    @Override
    public void buyCar() {
        Log.e("buyCar", "買一輛車花費了-->" + cash + "元");
    }
}

3.)聲明一個買車代理汽車4S店,同樣也實現買車接口,必須接受客戶下單

public class BuyCarProxy implements IBuyCar{
    private Customer customer;//接收買車客戶

    public BuyCarProxy(Customer customer){
        this.customer=customer;//接收買車客戶
    }

    @Override
    public void buyCar() {//實現為客戶買車
        customer.buyCar();
    }
}

4.)創建一個客戶端,模擬一次買車

  Customer customer=new Customer();
  customer.setCash(120000);
  BuyCarProxy buyCarProxy=new BuyCarProxy(customer);
  buyCarProxy.buyCar();

5.)通過代理模式實現權限控制

  通過上面的例子,我們可能有個疑問,難道就不能直接去廠家買車嗎?當然可以,如果在使用場景中實現類能滿足要求時,我們當然可以直接實現類,但當實現類不能滿足要求,要擴展需求,根據開閉原則你又不能修改實現類代碼,這時你就用代理類。比如購買一輛車我們要對客戶進行一個購車款審核,如果符合條件就買車,不符合要求我們就告知客戶購車款不足。

 @Override
    public void buyCar() {//實現為客戶買車
        int cash=customer.getCash();
        if(cash<100000){
            Log.e("buyCar","你的錢不夠買一輛車");
            return;
        }
        customer.buyCar();
    }

實現場景

Customer customer=new Customer();
customer.setCash(120000);
BuyCarProxy buyCarProxy=new BuyCarProxy(customer);
buyCarProxy.buyCar();

Customer customer1 =new Customer();
customer1.setCash(90000);
BuyCarProxy buyCarProxy1 =new BuyCarProxy(customer1);
buyCarProxy1.buyCar();

動態代理機制:

以上講的都是代理模式的靜態實現,所謂靜態代理就是自己要為要代理的類寫一個代理類,或者用工具為其生成的代理類,總之,就是程序運行前就已經存在的編譯好的代理類,這樣有時候會覺得非常麻煩,也導致非常的不靈活,相比靜態代理,動態代理具有更強的靈活性,因為它不用在我們設計實現的時候就指定某一個代理類來代理哪一個被代理對象,我們可以把這種指定延遲到程序運行時由JVM來實現

舉例:還是接着上面的例子

1.)首先我們要聲明一個動態代理類,實現InvocationHandler接口

public class DynamicProxy implements InvocationHandler {

    // 被代理類的實例
    Object obj;

    // 將被代理者的實例傳進動態代理類的構造函數中
    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    /**
     * 覆蓋InvocationHandler接口中的invoke()方法
     * 更重要的是,動態代理模式可以使得我們在不改變原來已有的代碼結構
     * 的情況下,對原來的“真實方法”進行擴展、增強其功能,並且可以達到
     * 控制被代理對象的行為,下面的before、after就是我們可以進行特殊
     * 代碼切入的擴展點了。
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        /*
         * before :doSomething();
         */
        Object result = method.invoke(this.obj, args);

        /*
         * after : doSomething();
         */
        return result;
    }
}

2.)具體實現

        //我們要代理的真實對象
        Customer customer = new Customer();
        //我們要代理哪個真實對象,就將該對象傳進去,最后是通過該真實對象來調用其方法的
        InvocationHandler handler = new DynamicProxy(customer);

        /*
         * 通過Proxy的newProxyInstance方法來創建我們的代理對象,我們來看看其三個參數
         * 第一個參數 handler.getClass().getClassLoader() ,我們這里使用handler這個類的ClassLoader對象來加載我們的代理對象
         * 第二個參數customer.getClass().getInterfaces(),我們這里為代理對象提供的接口是真實對象所實行的接口,表示我要代理的是該真實對象,這樣我就能調用這組接口中的方法了
         * 第三個參數handler, 我們這里將這個代理對象關聯到了上方的 InvocationHandler 這個對象上
         */
        IBuyCar buyCar = (IBuyCar) Proxy.newProxyInstance(handler.getClass().getClassLoader(), customer.getClass().getInterfaces(), handler);
        buyCar.buyCar();

3.)動態代理好處

使用Java動態代理機制的好處:

1、減少編程的工作量:假如需要實現多種代理處理邏輯,只要寫多個代理處理器就可以了,無需每種方式都寫一個代理類。

2、系統擴展性和維護性增強,程序修改起來也方便多了(一般只要改代理處理器類就行了)。

總結:

   通過上面的應用例子我們學習了代理模式的具體使用場景。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM