代理模式是一種結構型設計模式,它可以讓我們通過一個代理物件來存取一個真實的目標物件,從而實現對目標物件的功能擴充套件或保護。代理模式的主要角色有三個:
代理模式可以幫助我們解決以下幾種問題:
根據代理模式的定義,我們可以用以下的類圖來表示它的結構:
其中,Client是使用者端類,它需要使用Subject介面提供的方法。Proxy是代理類,它持有一個RealSubject的參照,並且實現了Subject介面。RealSubject是真實類,它也實現了Subject介面,並且定義了具體的業務邏輯。
代理模式有多種型別,例如靜態代理、動態代理等,代理模式也有自己的優缺點,使用時需要根據具體的場景和需求來選擇合適的型別和方式。
下面我們用Java程式碼來實現一個靜態代理的例子:
// 抽象主題介面
public interface Subject {
// 定義一個抽象方法
void request();
}
// 真實主題類
public class RealSubject implements Subject {
// 實現抽象方法
@Override
public void request() {
// 真實的業務邏輯
System.out.println("RealSubject is doing something...");
}
}
// 代理主題類
public class Proxy implements Subject {
// 持有一個真實主題的參照
private RealSubject realSubject;
// 構造方法,傳入一個真實主題物件
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
// 實現抽象方法
@Override
public void request() {
// 在呼叫真實主題之前,可以執行一些額外操作
System.out.println("Proxy is doing something before...");
// 呼叫真實主題的方法
realSubject.request();
// 在呼叫真實主題之後,可以執行一些額外操作
System.out.println("Proxy is doing something after...");
}
}
// 使用者端類
public class Client {
public static void main(String[] args) {
// 建立一個真實主題物件
RealSubject realSubject = new RealSubject();
// 建立一個代理物件,並傳入真實主題物件
Proxy proxy = new Proxy(realSubject);
// 使用代理物件來呼叫抽象方法
proxy.request();
}
}
執行結果如下:
Proxy is doing something before...
RealSubject is doing something...
Proxy is doing something after...
從執行結果可以看出,代理物件在呼叫真實物件的方法之前和之後,都執行了一些額外的操作,從而對真實物件進行了增強或控制。
動態代理是一種特殊的代理模式,它可以在執行時動態地建立代理物件,而不需要事先定義代理類。動態代理可以更靈活地適應不同的場景和需求,但是也更復雜和難以理解。
這個例子是使用JDK動態代理來實現一個紀錄檔代理,它可以在呼叫目標物件的方法之前和之後,記錄相關的紀錄檔資訊。程式碼如下:
// 抽象主題介面
public interface Subject {
// 定義一個抽象方法
void request();
}
// 真實主題類
public class RealSubject implements Subject {
// 實現抽象方法
@Override
public void request() {
// 真實的業務邏輯
System.out.println("RealSubject is doing something...");
}
}
// 紀錄檔處理器類,實現了InvocationHandler介面,用於定義代理邏輯
public class LogHandler implements InvocationHandler {
// 持有一個目標物件的參照
private Object target;
// 構造方法,傳入一個目標物件
public LogHandler(Object target) {
this.target = target;
}
// 實現invoke方法,用於呼叫目標物件的方法,並在之前和之後執行紀錄檔操作
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在呼叫目標物件之前,記錄開始時間
long startTime = System.currentTimeMillis();
System.out.println("開始執行" + method.getName() + "方法...");
// 呼叫目標物件的方法,並獲取返回值
Object result = method.invoke(target, args);
// 在呼叫目標物件之後,記錄結束時間和耗時
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("結束執行" + method.getName() + "方法,耗時" + duration + "毫秒");
// 返回結果
return result;
}
}
// 使用者端類
public class Client {
public static void main(String[] args) {
// 建立一個真實主題物件
RealSubject realSubject = new RealSubject();
// 建立一個紀錄檔處理器物件,並傳入真實主題物件
LogHandler logHandler = new LogHandler(realSubject);
// 使用Proxy類的靜態方法newProxyInstance來動態地建立一個代理物件,傳入真實主題物件的類載入器、介面和處理器
Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), logHandler);
// 使用代理物件來呼叫抽象方法
proxy.request();
}
}
執行結果如下:
開始執行request方法...
RealSubject is doing something...
結束執行request方法,耗時1毫秒
從執行結果可以看出,代理物件在呼叫真實物件的方法之前和之後,都執行了一些紀錄檔操作,從而對真實物件進行了增強。
優點:
缺點:
優點:
缺點:
代理模式是一種常用的結構型設計模式,它可以讓我們通過一個代理物件來間接存取一個真實物件,從而實現對目標物件的功能擴充套件或保護。代理模式有三個主要角色:抽象主題、真實主題和代理主題。代理模式有多種型別,例如靜態代理、動態代理、遠端代理、虛擬代理等。代理模式有自己的優缺點,使用時需要根據具體的場景和需求來選擇合適的型別和方式。