一、定義:
? ? ? ? 為其他對象提供一種代理以控制對這個對象的訪問。
二、角色組成:
? ? ? ? Subject抽象主題:聲明真是主題與代理的共同接口方法,可以是一個抽象類或接口。
? ? ? ? RealSubject真實主題:定義了代理表示的真實對象,執行具體的邏輯和方法。
? ? ? ? ProxySubject代理:持有對真實主題的引用,實現接口方法中調用真實主題對應的接口方法。
? ? ? ? Client客戶:使用代理的示例,通過調用代理的方法來實現對真實主題的調用。
三、代理類型:
? ? ? ? 1.靜態代理:手動創建代理類直接持有目標對象的引用。
? ? ? ? 2.動態代理:運行時動態生成代理類,如JDK的動態代理,CGLIB等。
? ? ? ? 3.遠程代理:跨進程通信的代理,如Android的AIDL機制。
四、簡單實現:
靜態代理
? ? ? ? 1.抽象主題
public interface FileLoader {
? ? String readFile(String path);
}
? ? ? ? 2.真實主題
public class RealFileLoader implements FileLoader {
? ? @Override
? ? public String readFile(String path) {
? ? ? ? // 模擬讀取文件內容
? ? ? ? return "File content: " + path;
? ? }
}
? ? ? ? 3.代理
public class FileLoaderProxy implements FileLoader {
? ? private RealFileLoader realFileLoader;
? ? private boolean hasPermission;
? ? public FileLoaderProxy(boolean hasPermission) {
? ? ? ? this.hasPermission = hasPermission;
? ? }
? ? @Override
? ? public String readFile(String path) {
? ? ? ? // 延遲初始化真實對象
? ? ? ? if (realFileLoader == null) {
? ? ? ? ? ? realFileLoader = new RealFileLoader();
? ? ? ? }
? ? ? ? // 權限校驗
? ? ? ? if (!hasPermission) {
? ? ? ? ? ? return "Error: Permission denied!";
? ? ? ? }
? ? ? ? // 調用真實對象方法
? ? ? ? return realFileLoader.readFile(path);
? ? }
}
????????4.客戶端調用
public class Main {
? ? public static void main(String[] args) {
? ? ? ? // 有權限的用戶
? ? ? ? FileLoader proxy1 = new FileLoaderProxy(true);
? ? ? ? System.out.println(proxy1.readFile("/data/test.txt"));?
? ? ? ? // 輸出:File content: /data/test.txt
? ? ? ? // 無權限的用戶
? ? ? ? FileLoader proxy2 = new FileLoaderProxy(false);
? ? ? ? System.out.println(proxy2.readFile("/data/secret.txt"));?
? ? ? ? // 輸出:Error: Permission denied!
? ? }
}
動態代理
? ? ? ? 1.抽象主題
public interface DataService {
? ? void saveData(String data);
? ? void deleteData(String id);
}
? ? ? ? 2.真實主題
public class RealDataService implements DataService {
? ? @Override
? ? public void saveData(String data) {
? ? ? ? System.out.println("Saving data: " + data);
? ? }
? ? @Override
? ? public void deleteData(String id) {
? ? ? ? System.out.println("Deleting data with ID: " + id);
? ? }
}
? ? ? ? 3.動態代理執行
public class LoggingHandler implements InvocationHandler {
? ? private Object target; // 目標對象
? ? public LoggingHandler(Object target) {
? ? ? ? this.target = target;
? ? }
? ? @Override
? ? public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
? ? ? ? // 記錄調用日志
? ? ? ? System.out.println("Method called: " + method.getName());
? ? ? ? if (args != null) {
? ? ? ? ? ? System.out.println("Arguments: " + Arrays.toString(args));
? ? ? ? }
? ? ? ? // 調用真實對象方法
? ? ? ? Object result = method.invoke(target, args);
? ? ? ? // 記錄返回結果
? ? ? ? System.out.println("Method completed: " + method.getName());
? ? ? ? return result;
? ? }
}
? ? ? ? 4.生成動態代理調用
public class Main {
? ? public static void main(String[] args) {
? ? ? ? // 創建真實對象
? ? ? ? DataService realService = new RealDataService();
? ? ? ? // 創建動態代理
? ? ? ? DataService proxy = (DataService) Proxy.newProxyInstance(
? ? ? ? ? ? realService.getClass().getClassLoader(),
? ? ? ? ? ? realService.getClass().getInterfaces(),
? ? ? ? ? ? new LoggingHandler(realService)
? ? ? ? );
? ? ? ? // 通過代理調用方法
? ? ? ? proxy.saveData("Hello, Proxy!");
? ? ? ? proxy.deleteData("123");
? ? }
}
五、優缺點
優點:
? ? ? ? 1.控制對象訪問,增強安全性。
? ? ? ? 2.支持延遲加載,優化性能。
? ? ? ? 3.解耦客戶端與目標對象
缺點:
? ? ? ? 1.增加代碼復雜度,需要額外增加代理類。
? ? ? ? 2.動態代理可能降低運行效率。
? ? ? ? 3.遠程代理需要處理網絡或跨進程問題。