代理模式的本質是一箇中介軟體,主要目的是解耦合服務提供者和使用者。使用者通過代理間接的訪問服務提供者,便於後者的封裝和控制。是一種結構性模式。
1.目的
為外部呼叫者提供一個訪問服務提供者的代理物件。
2.動機
限制對目標物件的直接訪問,降低耦合度。
3.優缺點
優點:
優點:
- 低耦合
- 易擴充套件
- 靈活度高
缺點:
- 間接訪問可能會延遲請求相應
- 增加工作量
4.分類
- 靜態代理
- 動態代理
代理類本身的實現可能並不簡單,加上每一個需要代理的物件均均需要實現一個代理類,其工作量本身比較大,易出錯。
所謂動態代理(DynamicProxy)是指在程式執行時動態的生成對目標物件的訪問介面。
本文主要介紹前者,關於後者可以參考JDK自帶的動態代理。
5.主要用途
代理模式在以下場景比較適用:
1、遠端代理。 2、虛代理。 3、保護代理。4、智慧指引代理。5、寫時複製(Copy-on-Write)代理。 6、快取代理。 7、防火牆代理。 8、同步化代理。
6.原理
下面是GoF介紹典型的代理模式UML類圖
Subject:
定義RealSubject對外的介面,且這些介面必須被Proxy實現,這樣外部呼叫proxy的介面最終都被轉化為對realsubject的呼叫。
RealSubject:
真正的目標物件。
Proxy:
目標物件的代理,負責控制和管理目標物件,並間接地傳遞外部對目標物件的訪問。
- Remote Proxy: 對本地的請求以及引數進行序列化,向遠端物件傳送請求,並對響應結果進行反序列化,將最終結果反饋給呼叫者;
- Virtual Proxy: 當目標物件的建立開銷比較大的時候,可以使用延遲或者非同步的方式建立目標物件;
- Protection Proxy: 細化對目標物件訪問許可權的控制;
7.實現
下面我們使用兩個例子來實際體驗一下代理模式的應用
網路代理
對於一些國內不能直接訪問的網站,合法的使用的網路代理可以實現對目標網站的訪問;
定義公共介面類Server:
public interface Server{ void visit(String url); }
代理伺服器ProxyServer:
public class ProxyServer implements Server{ private RealServer realServer; public ProxyServer(String serverName){ this.realServer = new RealServer(serverName); } @Override public void visit(String url) { realServer.visit(url); } }
目標伺服器RealServer:
public class RealServer implements Server { private String serverName; public RealServer(String serverName) { this.serverName = serverName; System.out.println("This is " + serverName); } @Override public void visit(String url) { response(url); } private void response(String res) { System.out.println("This is response of " + res + " from server:" + serverName); } }
演示:
public class Demo { public static void main(String[] args) { Server server = new ProxyServer("www.google.com"); server.visit("map.google.com"); } }
智慧指標引用計數
下面使用代理模式簡單的模擬指標引用計數問題
介面類Obj:
public interface Obj{ void GetAttr(); Obj copy(); void delete(); }
智慧指標類SmartPointer:
public class SmartPointer implements Obj{ private RealObj realObj; private int counter = 1; public SmartPointer(String objType){ this.realObj = new RealObj(objType); } @Override public void GetAttr() { if(counter > 0) { realObj.GetAttr(); } System.out.println("Smart Ref: " + counter); } public Obj copy() { if(counter > 0) { counter += 1; return this; } System.out.println("Invalid Pointer!"); return null; } public void delete() { if(counter > 0) { counter -= 1; if(0 == counter) { realObj = null; } } else { System.out.println("Invalid Pointer!"); } } }
被引用物件類RealObj:
public class RealObj implements Obj { private String objType; public RealObj(String objType) { this.objType = objType; System.out.println("Create Obj: " + objType); } @Override public void GetAttr() { System.out.println("get attr of real obj " + objType); } @Override public Obj copy() { // TODO Auto-generated method stub return null; } @Override public void delete() { // TODO Auto-generated method stub } }
參考:
GoF《Design Patterns: Elements of Reusable Object-Oriented Software》
https://www.runoob.com/design-pattern/proxy-pattern.html