1. 程式人生 > 程式設計 >詳解JAVA設計模式之代理模式

詳解JAVA設計模式之代理模式

什麼是設計模式(Design Pattern)?

  設計模式是一套被反覆使用,多數人知曉的,經過分類編目的,程式碼設計經驗的總結。

代理模式的定義?

  代理模式就是為其他物件提供一種代理,以控制對這個物件的訪問。

  代理物件起到中介作用,可去掉功能服務或增加額外的服務。

代理物件和目標物件的關係?

  代理物件:增強後的物件

  目標物件:被增強的物件

  他們不是絕對的,會根據情況發生變化。

代理模式的兩種實現方式?

  1.靜態代理:代理和被代理物件在代理之前是確定的,它們都實現相同的介面或者繼承相同的抽象類。

  2.動態代理:JDK通過介面反射得到位元組碼,然後把位元組碼轉換成class(通過native方法)

靜態代理實現的兩種方式?

  使用繼承方式實現和使用聚合方式實現。

  繼承:代理物件繼承目標物件,重寫需要增強的方法。缺點:代理類過多,產生類爆炸。

  聚合:目標物件和代理物件實現同一個介面,代理物件當中要包含目標物件。

動態代理的實現方式?

  Java動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類:

    1.Interface InvocationHandler : 該介面中僅定義了一個方法,public Object invoke(Object obj,Method method,Object[] args),在實際使用時,第一個引數obj一般是指代理類,method是被代理的方法,args是該方法的引數陣列,這個抽象方法在代理類中動態實現。

    2.Proxy 該類即為動態代理類,static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理類的一個例項,返回後的代理類可以當做被代理類使用(可使用被代理類在介面中宣告過的方法)

    所謂的動態代理是這樣一種class:它是在執行時生成的class,該class需要實現一組interface,使用動態代理類時,必須實現InvocationHandler介面。

JDK動態代理和CGLIB動態代理的區別?

  1.JDK動態代理只能代理實現了介面的類,沒有實現介面的類不能實現JDK的動態代理。

  2.CGLIB動態代理針對類來實現代理的,對指定目標類產生一個子類,通過方法攔截技術攔截所有的父類方法的呼叫。

動態代理實現的思路:

  1.宣告一段原始碼(動態產生代理)

  2.編譯原始碼(JDK Compiler API ),產生新的類(代理類)

  3.將這個類load到記憶體中,產生一個新的物件(代理物件)

  4.return 代理物件。

使用靜態代理的例子:

  1.首先建立業務邏輯介面

/**
 * 介面
 * @author Administrator
 *
 */
public interface Moveable {
  /**
   *
   * 介面中的方法
   * @Description: TODO
   * @returnType: void
   */
  void move();
}

  2.建立實現類,實現介面中的方法

/**
 * 實現類
 * @author Administrator
 *
 */
public class Car implements Moveable {

  @Override
  public void move() {
    //實現開車
    try {
      Thread.sleep(new Random().nextInt(1000));
      System.out.println("汽車行駛中...");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

}

  3.使用繼承方式實現對實現類的代理

/**
 * 使用繼承方式實現代理
 * @author Administrator
 *
 */
public class Car2 extends Car {

  /* (non-Javadoc)
   * @see com.wk.design.proxy.Car#move()
   * 直接呼叫父類的move方法,這樣就形成了一個Car2對Car的代理
   */
  @Override
  public void move() {
    long startTime = System.currentTimeMillis();
    System.out.println("汽車開始行駛...");
    //使用繼承的方式呼叫父類的move()方法
    super.move();
    long endTime = System.currentTimeMillis();
    System.out.println("汽車行駛結束... 汽車行駛時間:"+(endTime-startTime)+"毫秒。");
  }

}

  4.建立測試類

/**
 * 測試類
 * @author Administrator
 *
 */
public class Test {

  public static void main(String[] args) {
//    Car car = new Car();
//    car.move();

    //使用繼承方式實現代理
    Moveable car2 = new Car2();
    car2.move();

    //使用聚合方式實現代理
//    Car car = new Car();
//    Moveable car3 = new Car3(car);
//    car3.move();

  }
}

  5.使用聚合方式實現對實現類的代理

    日誌代理類

/**
 *
 * 日誌代理類
 * @author Administrator
 *
 */
public class CarLogProxy implements Moveable {

  /**
   * 使用介面宣告代理類
   */
  private Moveable m;
  /**
   * 通過構造方法的引數傳入代理類
   * @param m
   */
  public CarLogProxy(Moveable m) {
    super();
    this.m = m;
  }

  @Override
  public void move() {
    System.out.println("日誌開始");
    //呼叫代理類的方法
    m.move();
    System.out.println("日誌結束");

  }

}

    時間代理類

/**
 * 時間代理類
 * @author Administrator
 *
 */
public class CarTimeProxy implements Moveable {

  /**
   * 使用介面宣告代理類
   */
  private Moveable m;
  /**
   * 通過構造方法的引數傳入代理類
   * @param m
   */
  public CarTimeProxy(Moveable m) {
    super();
    this.m = m;
  }

  @Override
  public void move() {
    long startTime = System.currentTimeMillis();
    System.out.println("汽車開始行駛...");
    //呼叫代理類的方法
    m.move();
    long endTime = System.currentTimeMillis();
    System.out.println("汽車行駛結束... 汽車行駛時間:"+(endTime-startTime)+"毫秒。");
  }

}

  6.建立聚合方式測試類

/**
 * 聚合代理測試類
 * @author Administrator
 *
 */
public class TestJuHeProxy {
  public static void main(String[] args) {
    Car car = new Car();
    //先記錄日誌,再記錄時間
//    CarTimeProxy ctp = new CarTimeProxy(car);
//    CarLogProxy clp = new CarLogProxy(ctp);
//    clp.move();

    //先記錄時間,再記錄日誌
    CarLogProxy clp = new CarLogProxy(car);
    CarTimeProxy ctp = new CarTimeProxy(clp);
    ctp.move();
  }

}

使用JDK動態代理實現的例子:

  1.建立一個實現介面InvocationHandler的類,它必須實現invoke()方法。

  2.建立被代理類及介面

  3.呼叫Proxy的靜態方法,建立一個代理類

  4.通過代理呼叫方法

/**
 * 使用jdk的動態代理
 * @author Administrator
 *
 */
public class TimeHandler implements InvocationHandler {

  /**
   * 被代理物件
   */
  private Object target;

  public TimeHandler(Object target) {
    super();
    this.target = target;
  }

  /**
   * 引數:
   * proxy : 被代理物件
   * method : 被代理物件的方法
   * args : 方法的引數
   * 返回值:
   * Object 方法的返回值
   */
  @Override
  public Object invoke(Object proxy,Object[] args) throws Throwable {
    //在執行被代理物件的方法之前執行自己的邏輯
    long startTime = System.currentTimeMillis();
    System.out.println("汽車開始行駛...");
    //執行被代理物件的方法
    method.invoke(target);
    //在執行被代理物件的方法之後執行自己的邏輯
    long endTime = System.currentTimeMillis();
    System.out.println("汽車行駛結束... 汽車行駛時間:"+(endTime-startTime)+"毫秒。");
    return null;
  }

}
 /**
  * JDK動態代理測試類
  * @author Administrator
  *
  */
 public class JdkProxyTest {
 
   public static void main(String[] args) {
     Car car = new Car();
     InvocationHandler h = new TimeHandler(car);
     Class<?> cls = car.getClass();
     /**
     * 引數:
     *   loader : 類載入器
     * interfaces : 實現介面
     * h InvocationHandler
     */
     Moveable m= (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h);
     //執行被代理類的方法
     m.move();
   }
 
 }

使用CGLIB動態代理實現的例子:

  1.建立代理類,實現MethodInterceptor介面

  2.使用Enhancer類建立代理方法

  3.建立被代理類,並編寫代理方法

  4.通過代理呼叫方法

/**
 * 使用cglib動態代理
 * @author Administrator
 *
 */
public class Train {
  public void move(){
    System.out.println("火車行駛中。。。");
  }
}
public class CglibProxy implements MethodInterceptor {

  private Enhancer enhancer = new Enhancer();
  //建立代理類方法
  public Object getProxy(Class clazz){
    //設定建立子類的類
    enhancer.setSuperclass(clazz);
    //回撥函式
    enhancer.setCallback(this);
    //建立並返回子類的例項
    return enhancer.create();
  }
  /**
   * 作用:攔截所有目標類方法的呼叫
   * obj : 目標類的例項
   * m : 目標方法的反射物件
   * args : 方法的引數
   * proxy : 代理類的例項
   */
  @Override
  public Object intercept(Object obj,Method m,Object[] args,MethodProxy proxy) throws Throwable {
    //在呼叫方法時實現自己的業務邏輯
    System.out.println("日誌開始...");
    //代理類呼叫父類的方法
    proxy.invokeSuper(obj,args);
    //呼叫方法之後實現自己的業務邏輯
    System.out.println("日誌結束...");
    return null;
  }
}
 /**
  * 使用cglib動態代理的測試類
  * @author Administrator
  *
  */
 public class CglibProxyTest {
 
   public static void main(String[] args) {
     CglibProxy proxy = new CglibProxy();
     //傳入要代理的類
     Train t = (Train)proxy.getProxy(Train.class);
     //執行方法
     t.move();
   }
 
 }

以上就是詳解JAVA設計模式之代理模式的詳細內容,更多關於JAVA 代理模式的資料請關注我們其它相關文章!