代理模式是一種比較常用的設計模式,在某些場景下,我們要使用某些功能,並不是直接呼叫實現類,而是通過代理類來完成。通過代理,我們可以隱藏實現類的細節,在不修改實現類的基礎上,還可以增加額外的功能,如校驗,計算執行時長等。代理模式在現實生活中也是顯而易見的,如房屋中介,代購,律師等。當我們要打一場官司時,我們自己對法律不是很瞭解,但是我們可以請專業的律師為我們提供代理,讓他來幫我們打這場官司。
專案地址
靜態代理
我們所說的代理,一般是指靜態代理,即一個實現類對應一個代理類,一一對應的關係。我們用一場官司來說明靜態代理。
首先,我們定義一個介面,表示我們要做的事情–打官司。
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();
}
}複製程式碼