在軟體系統中,服務提供者(Real Subject)應專注於核心業務邏輯。但實際開發常需在方法呼叫前後加入日誌記錄、效能計數、存取控制等橫切關注點。若直接耦合在業務類中,會違反「單一職責原則」,導致程式碼膨脹且難以維護。
計數代理模式的核心思想:將這些附加功能封裝在獨立的代理物件中,代理實現與真實主題相同的介面,客戶端透過代理間接存取真實物件,代理在轉發呼叫前後執行額外邏輯。

圖中關鍵角色:
public interface OrderIF {
Vector getAllOrders();
}
public class Order implements OrderIF {
public Vector getAllOrders() {
FileUtil fileUtil = new FileUtil();
return fileUtil.fileToVector("orders.txt");
}
}
public class OrderProxy implements OrderIF {
private int counter = 0;
public Vector getAllOrders() {
Order realOrder = new Order();
counter++;
long start = System.currentTimeMillis();
Vector result = realOrder.getAllOrders();
long elapsed = System.currentTimeMillis() - start;
String logMsg = "Iteration=" + counter + "::Time=" + elapsed + "ms";
new FileUtil().writeToFile("log.txt", logMsg, true, true); // 追加寫入
return result;
}
}
public class MainApp {
public static void main(String[] args) {
OrderIF proxy = new OrderProxy(); // 客戶端只依賴介面
proxy.getAllOrders();
proxy.getAllOrders();
proxy.getAllOrders();
proxy.getAllOrders(); // 日誌將記錄 4 次呼叫及各自耗時
}
}
| 優勢 | 說明 |
|---|---|
| 職責分離 | 業務邏輯與輔助功能(日誌、計數、快取、權限檢查)解耦 |
| 開閉原則 | 新增代理功能無需修改 RealSubject |
| 透明性 | 客戶端無感知代理存在,程式碼零修改切換 |
| 彈性組合 | 可疊加多層代理(如:計數代理 → 快取代理 → 安全代理 → 真實物件) |
適用場景:
Java 內建 java.lang.reflect.Proxy 與 InvocationHandler 可在執行期動態生成代理類,避免為每個介面手寫代理類。Spring AOP 底層即基於此機制(JDK 動態代理 / CGLIB)。
// 動態代理範例雛形
OrderIF proxy = (OrderIF) Proxy.newProxyInstance(
OrderIF.class.getClassLoader(),
new Class[]{OrderIF.class},
(proxyObj, method, args) -> {
long start = System.nanoTime();
Object result = method.invoke(realOrder, args);
log.info("{} 耗時 {} ms", method.getName(), (System.nanoTime()-start)/1e6);
return result;
}
);
計數代理模式以「組合大於繼承」的思想,將橫切關注點從核心業務中剝離,是構建整潔、可維護、可擴展系統的基石模式之一。理解其靜態結構與動態代理演進,有助於深入掌握現代框架(Spring、Dubbo 等)的底層設計哲學。