Java進階知識 —— Java設計模式之代理模式

代理模式是常用的Java設計模式,它的特徵是代理類與委託類有同樣的接口,一個代理類的對象與一個委託類的對象關聯,代理類的對象本身並不真正實現服務,而是通過調用委託類的對象的相關方法,來提供特定的服務,代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及事後處理消息等。

簡單舉個例子,例如你現在正在看電視,但是老師佈置了作業,你又想看電視又要完成作業,你靈機一動,讓哥哥幫你寫,你開心的看完電視,作業也寫完了,這種讓別人代替你完成的某種任務的行爲就是代理模式

按照代理類的創建時期,代理類可分爲兩種。

靜態代理:

由程序員創建或由特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。實現類和代理類實現同一個接口,將實現類對象傳遞給代理類,代理類的實現方法實際是由實現類完成操作的。

public interface Subject {
    void visit();
}

//執行者,代理者
public class RealSubject implements Subject {

    private String name = "proxy";
    @Override
    public void visit() {
        System.out.println(name);
    }
}

//委託者,被代理者
public class ProxySubject implements Subject{
    private Subject subject;
    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void visit() {
        subject.visit();
    }
}

//執行
public class Client {
    public static void main(String[] args) {
    	//真正執行的是代理者
        ProxySubject subject = new ProxySubject(new RealSubject());
        subject.visit();
    }
}

動態代理

動態代理有別於靜態代理,是根據代理的對象,動態創建代理類。這樣,就可以避免靜態代理中代理類接口過多的問題。動態代理是實現方式,是通過反射來實現的,藉助Java自帶的java.lang.reflect.Proxy,通過固定的規則生成。
其步驟如下:

  • 編寫一個委託類的接口,即靜態代理的(Iuser接口)
  • 實現一個真正的委託類,即靜態代理的(UserImpl類)
  • 創建一個動態代理類,實現InvocationHandler接口,並重寫該invoke方法
    在測試類中,生成動態代理的對象。

第一二步驟,和靜態代理一樣,不過說了。第三步,代碼如下:
動態代理Demo

public interface Iuser {
   void eat(String s);
 }
 //委託類,執行者
public class UserImpl implements Iuser {
  @Override
  public void eat(String s) {
    System.out.println("我要喫"+s);
  }
}

public class DynamicProxy implements InvocationHandler {
  private Object object;//用於接收具體實現類的實例對象
  //使用帶參數的構造器來傳遞具體實現類的對象
  public DynamicProxy(Object obj){
    this.object = obj;
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
    Object result = method.invoke(object, args);
    return result;
  }
}

public class ProxyTest {
  public static void main(String[] args) {
    Iuser user = new UserImpl();
    InvocationHandler h = new DynamicProxy(user);
    Iuser proxy = (Iuser) Proxy.newProxyInstance(user..getClass().getClassLoader(), new Class[]{Iuser.class}, h);
    proxy.eat("蘋果");
  }
}

創建動態代理的對象,需要藉助Proxy.newProxyInstance。該方法的三個參數分別是:

  • ClassLoader loader表示當前使用到的appClassloader。
  • Class<?>[] interfaces表示目標對象實現的一組接口。
  • InvocationHandler h表示當前的InvocationHandler實現實例對象。
    簡單介紹了 靜態代理和動態代理的區別
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章