首頁 > Java > java教程 > 主體

Java中的代理模式詳解及實例程式碼

高洛峰
發布: 2017-02-07 13:08:03
原創
1380 人瀏覽過

java 代理模式詳解

前言:

在某些情況下,一個客戶不想或不能直接引用一個對象,此時可以透過一個稱之為「代理」的第三者來實現間接引用。代理對象可以在客戶端和目標對象之間起到 中介的作用,並且可以透過代理對象去掉客戶不能看到 的內容和服務或添加客戶需要的額外服務。

簡單來說代理模式就是透過一個代理對象去存取一個實際對象,並且可以像裝飾模式一樣為對象添加一些功能。

靜態代理

所謂靜態代理即在程式運行前代理類別就已經存在,也就是說我們編寫程式碼的時候就已經把代理類別的程式碼寫好了,而動態代理程式則是在程式運行時自動生成代理類。

描述太過抽象,看一下程式碼就明白是怎麼回事了

main

public class Main {
 
  public static void main(String[] args) {
    Water water = new Water();
    WaterProxy waterProxy = new WaterProxy(water);
    waterProxy.drink();
  }
 
}
登入後複製

   

介面

//代理类与被代理类共同实现的接口
public interface Drink {
  void drink();
}
登入後複製

代理類

//被代理的类
public class Water implements Drink {
 
  @Override
  public void drink() {
    System.out.println("drink water");
  }
 
}
登入後複製

   

執行結果

//代理类
//与被代理类实现同一个接口
public class DrinkProxy implements Drink {
   
  private Drink drinkImpl;
   
  //通过构造函数传入Water对象
  public DrinkProxy(Drink drinkImpl) {
    this.drinkImpl = drinkImpl;
  }
   
  @Override
  public void drink() {
    //在执行被代理对象的方法前做一些事情
    System.out.println("before drink");
    //执行被代理对象的方法
    drinkImpl.drink();
    //在执行被代理对象的方法后做一些事
    System.out.println("after drink");
  }
 
}
登入後複製

   

動態代理

有時鐵打的代理類,流水的被代理類。而採用靜態代理就只能代理實作了同一介面的類,如果要代理任意類則必須寫很多重複的代理類。此時我們可以採用動態代理,Java已經為實作動態代理提供了一套比較方便的工具。

java.lang.reflect.Proxy類別中可以動態產生代理物件的方法

before drink
drink water
after drink
登入後複製

   

InvocationHandler介面

/**
   *返回实现了指定接口的对象,调用代理对象的方法会调用
   *InvocationHandler的invoke方法
   *
   * @param  loader 获取代理类所使用的类加载器
   * @param  interfaces 代理类所要实现的接口
   * @param  h 实现了InvocationHandler接口的对象
   * @return 代理对象
   */
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)
登入後複製

InvocationHandler介面的實作類別

/**
 *每个代理类都有一个关联的InvocationHandler
 *当代理对象执行一个方法的时候会直接执行invoke方法
 */
public interface InvocationHandler {
 
  /**
   * @param  调用该方法的代理对象
   * @param  method 代理对象所调用的方法
   * @param  args 调用的方法的参数
   * @return 调用的方法的返回值
   */
  public Object invoke(Object proxy, Method method, Object[] args)
}
登入後複製

   

Main

public class CommonInvocationHandler implements InvocationHandler {
   
  //被代理的对象
  private Object proxied;
   
  public CommonInvocationHandler(Object proxied) {
    this.proxied = proxied;
  }
   
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //在调用被代理对象的方法前做一些事情
    System.out.println("before doing something");
    //调用被代理对象的方法
    Object result = method.invoke(proxied, args);
    //在调用被代理对象的方法后做一些事情
    System.out.println("after doing something");;
    return result;
  }
 
}
登入後複製

   

public class Main {
 
  public static void main(String[] args) {
    //被代理的对象
    Water water = new Water();
    //动态获取代理对象
    Drink waterProxy =
        (Drink) Proxy.newProxyInstance(water.getClass().getClassLoader(),
            water.getClass().getInterfaces(),
            new CommonInvocationHandler(water));
    //通过代理对象调用方法
    waterProxy.drink();
  }
 
}
登入後複製
被代理對象,但是必須有相應的接口(沒有實現接口的類別可以使用cglib實現動態代理)才可以動態取得代理物件。像最近比較火的Retrofit就直接透過聲明好的介面使用動態代理進行網路請求。

範例

簡單的模擬一下retrofit

POST注

Main

before doing something
drink water
after doing something
登入後複製
   

感謝閱讀,希望能幫助大家,謝謝大家對本站的支持!

更多Java中的代理模式詳解及實例代碼相關文章請關注PHP中文網!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!