讓我們打一場動態代理的官司–Java動態代理

沉默的範大叔發表於2019-01-29

代理模式是一種比較常用的設計模式,在某些場景下,我們要使用某些功能,並不是直接呼叫實現類,而是通過代理類來完成。通過代理,我們可以隱藏實現類的細節,在不修改實現類的基礎上,還可以增加額外的功能,如校驗,計算執行時長等。代理模式在現實生活中也是顯而易見的,如房屋中介,代購,律師等。當我們要打一場官司時,我們自己對法律不是很瞭解,但是我們可以請專業的律師為我們提供代理,讓他來幫我們打這場官司。

專案地址

github.com/uncleleonfa…

靜態代理

我們所說的代理,一般是指靜態代理,即一個實現類對應一個代理類,一一對應的關係。我們用一場官司來說明靜態代理。
首先,我們定義一個介面,表示我們要做的事情–打官司。

interface Subject {
    void lawsuit();
}複製程式碼

然後實現該介面

public class RealSubject implements Subject {
    @Override
    public void lawsuit() {
        System.out.println("打官司");
    }
}複製程式碼

但是我們對這個實現是不知道的,因為我們不知道如何打官司,所以這裡需要一個代理律師:

public class ProxyLawyer implements Subject{

    private Subject subject;

    public ProxyLawyer(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void lawsuit() {
        before();
        subject.lawsuit();
        after();
    }

    private void before() {
        System.out.println("籤合同");
    }

    private void after() {
        System.out.println("收佣金");
    }
}複製程式碼

代理律師也來實現lawsuite介面,並且打官司前先簽合同,打完官司後收取佣金。
最後,我們通過代理律師來打這場官司。

public class Main {
    public static void main(String[] args) {
        System.out.println("-------靜態代理-------");
        Subject subject = new RealSubject();
        ProxyLawyer proxyLawyer = new ProxyLawyer(subject);
        proxyLawyer.lawsuit();
}複製程式碼

動態代理

靜態代理是一對一的關係,一個實現類對應一個代理類,假設我要打一個民事訴訟,就要有個民事訴訟的代理律師,要打一個刑事訴訟,就要有個刑事訴訟律師。

//民事訴訟
interface CivilSubject {
    void civilLawsuit();
}

//民事訴訟實現
public class RealCivilSubject implements CivilSubject {
    @Override
    public void civilLawsuit() {
        System.out.println("民事訴訟");
    }
}

//民事訴訟代理律師
public class CivilProxyLawyer implements CivilSubject{

    private CivilSubject civilSubject;

    public CivilProxyLawyer(CivilSubject subject) {
        civilSubject = subject;
    }

    @Override
    public void civilLawsuit() {
        before();
        civilSubject.civilLawsuit();
        after();
    }
    ........
}

//刑事訴訟
public interface CriminalSubject {
    void criminalSubject();
}

//刑事訴訟實現
public class RealCriminalSubject implements CriminalSubject {
    @Override
    public void criminalSubject() {
        System.out.println("刑事訴訟");
    }
}

//刑事訴訟代理律師
public class CriminalProxyLawyer implements CriminalSubject{

    private CriminalSubject criminalSubject;

    public CriminalProxyLawyer(CriminalSubject subject) {
        criminalSubject = subject;
    }

    @Override
    public void criminalSubject() {
        before();
        criminalSubject.criminalSubject();
        after();
    }
    .......
}複製程式碼

這裡存在的問題是,民事訴訟的代理律師只能代理民事訴訟,不能代理刑事訴訟,刑事訴訟的代理律師只能代理刑事訴訟,不能代理民事訴訟,二者只能各司其職。但是一位律師是否代理各類訴訟呢?當然是可以的。另外,從程式碼角度看,如果新增一類訴訟,就又得新加一個代理類,程式碼量會更加,在代理類中的方法before()和after()方法都是重複的,不能被複用。那怎麼解決這些問題了?這裡就需要用到動態代理了。

動態代理不需要事先就建立代理類,而是根據需求動態地建立。就相當於一個律師,根據訴訟的需求而轉換成不同的代理律師,不管訴訟型別的數目更加多少,律師只有一個。從程式碼角度講就不會增加代理律師類,律師的裡面公共的方法就能得到複用。

接下來我們來完成Java的動態代理,首先定義一個動態代理律師類DynamicProxyLawyer,他需要實現InvocationHandler介面,在invoke方法中觸發代理方法的呼叫。

public class DynamicProxyLawyer implements InvocationHandler {

    //代理的真實物件
    private Object subject;

    public DynamicProxyLawyer(Object subject) {
        this.subject = subject;
    }

    /**
     * @param method 所代理的真實物件某個方法的Method物件
     * @param args 所代理的真實物件某個方法接受的引數
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        method.invoke(subject, args);
        after();
        return null;
    }

    private void before() {
        System.out.println("籤合同");
    }

    private void after() {
        System.out.println("收佣金");
    }
}複製程式碼

接下來,我們可以使用這個動態代理律師來代理各種訴訟了。

public class Main {

    public static void main(String[] args) {

        System.out.println("-------動態代理--------");
        //動態建立一個民事訴訟代理的物件,該代理實現了介面CivilSubject
        CivilSubject civilProxy = (CivilSubject) Proxy.newProxyInstance(
                civilSubject.getClass().getClassLoader(),
                new Class[]{CivilSubject.class},
                new DynamicProxyLawyer(civilSubject)
        );
        civilProxy.civilLawsuit();
        //動態建立了一個刑事訴訟代理的物件,該代理實現了介面CriminalSubject
        CriminalSubject criminalProxy = (CriminalSubject) Proxy.newProxyInstance(
                criminalSubject.getClass().getClassLoader(),
                new Class[]{CriminalSubject.class},
                new DynamicProxyLawyer(criminalSubject)
        );
        criminalProxy.criminalSubject();
    }
}複製程式碼

相關文章