Java設計模式之代理模式


代理模式是Java常見的設計模式之一。所謂代理模式是指客戶端並不直接調用實際的對象,而是通過調用代理,來間接的調用實際的對象。
為什么要采用這種間接的形式來調用對象呢?一般是因為客戶端不想直接訪問實際的對象,或者訪問實際的對象存在困難,因此通過一個代理對象來完成間接的訪問。
在現實生活中,這種情形非常的常見,比如請一個律師代理來打官司。
下面例子的代碼可以訪問源碼。歡迎star,歡迎fork

代理模式的UML圖

從UML圖中,可以看出代理類與真正實現的類都是繼承了抽象的主題類,這樣的好處在於代理類可以與實際的類有相同的方法,可以保證客戶端使用的透明性。

代理模式的實現

代理模式可以有兩種實現的方式,一種是靜態代理類,另一種是各大框架都喜歡的動態代理。下面我們主要講解一下這兩種代理模式

靜態代理

我們先看針對上面UML實現的例子,再看靜態代理的特點。
Subject接口的實現

public interface Subject {
    void visit();
}

實現了Subject接口的兩個類:

public class RealSubject implements Subject {

    private String name = "byhieg";
    @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();
    }
}

通過上面的代理代碼,我們可以看出代理模式的特點,代理類接受一個Subject接口的對象,任何實現該接口的對象,都可以通過代理類進行代理,增加了通用性。但是也有缺點,每一個代理類都必須實現一遍委托類(也就是realsubject)的接口,如果接口增加方法,則代理類也必須跟着修改。其次,代理類每一個接口對象對應一個委托對象,如果委托對象非常多,則靜態代理類就非常臃腫,難以勝任。

動態代理

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

  1. 編寫一個委托類的接口,即靜態代理的(Subject接口)
  2. 實現一個真正的委托類,即靜態代理的(RealSubject類)
  3. 創建一個動態代理類,實現InvocationHandler 接口,並重寫該invoke方法
  4. 在測試類中,生成動態代理的對象。

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

public class DynamicProxy implements InvocationHandler {
    private Object object;
    public DynamicProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(object, args);
        return result;
    }
}

第四步,創建動態代理的對象

Subject realSubject = new RealSubject();
DynamicProxy proxy = new DynamicProxy(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new  Class[]{Subject.class}, proxy);
subject.visit();

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

  • ClassLoader loader表示當前使用到的appClassloader。
  • Class<?>[] interfaces表示目標對象實現的一組接口。
  • InvocationHandler h表示當前的InvocationHandler實現實例對象。

關於動態代理的使用,我們就介紹到這里。關於動態代理的實現、借助非JDK庫實現動態代理、以及他們的優缺點放到以后再介紹。


免責聲明!

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



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