代理模式(Proxy)
代理模式是常用的 JAVA 設計模式,它的特徵是代理類與委託類實現同樣的接口。代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及事後 處理消息等。
代理類與委託類之間通常會存在關聯關係,一個代理類的對象與一個委託類的對象關聯,代理類的對象本身並不真正實現服務,而是通過調用委託類的對象的相關方法,來提供特定的服務。
作用
給某個對象提供一個代理對象,並由代理對象控制原對象的引用。代理對象和真實對象實現相同的接口,使得任何使用真實對象的地方都可以使用代理對象,代理對象內部含有對真實對象的引用,再將調用傳遞給真實對象之前或之後執行一些額外的操作,達到控制真實對象的目的。
本質
控制對象的訪問。使用場景
代理模式使用場景非常多,如:面向切面編程(Spring中的AOP),
虛代理模式(hibernate中的懶加載),
保護代理(權限服務控制),
遠程代理(Java中的RMI技術)等。
代理模式的分類
按照代理的創建時期,代理類可以分爲兩種:(1)靜態代理: 由程序員創建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
(2)動態代理: 在程序運行時,運用反射機制動態創建而成。
按照代理用途來分類:
(1) 虛代理: 根據需求來創建開銷很大的對象,該對象只有在需要的時候纔會被真正的被創建。
(2) 遠程代理: 用來在不同的地址空間上代表同一對象,這個不同的地址空間可以使在本機也可以是在其他機器上。在Java裏面最典型的就是RMI技術。
(3) 保護代理: 控制原始對象的訪問,如果有需要,可以給不同的用戶提供不同的訪問權限,以控制他們對原始對象的訪問。
(4) Cache代理: 爲那些昂貴操作的結構提供臨時的存儲空間,以便多個客戶端可以共享這些結果。
(5) 智能代理: 在訪問對象時執行一些附加操作,比如,對指向實際對象的引用計數,第一次引用一個持久對象時,將它裝入內存等。
(6) 防火牆代理: 保護對象不被惡意程序訪問和操作。
(7) 同步代理: 使多個用戶能夠同時訪問目標對象而不發生衝突。
(8) Copy-on-write代理:在客戶端操作的時候,只有對象確實改變了纔會真的拷貝一個目標對象,算是虛代理的一個分支。
示例代碼
一般情況下代理模式需要三個角色
A. 真實角色:也就是我們需要引用的那個類。
B. 抽象角色:主要用來聲明代理類和真實類的共同接口。代理類和真實類都需要實現該接口。
C. 代理角色:代理角色內部包含對真實角色的引用,從而使客戶端可以操作真實的對象,同時代理角色和真實角色擁有相同的接口以便任何時候都能替代真實對象。同時還可以附加另外的操作。
在上圖中:
IProxy 是真實角色
Proxy 是抽象角色
ProxyStatic 和 ProxyDynamic 都是代理角色。
靜態代理:
/*
* 文 件 名: ProxyStatic.java
* 修 改 人: cKF61853
* 修改時間: 2012-12-12
*/
package cn.fareast.proxy;
import cn.fareast.proxy.iface.IProxy;
/**
* 靜態代理實現(靜態代理實現類)
*
* @author cKF61853
*/
public class ProxyStatic implements IProxy
{
//代理接口
IProxy proxy;
/**
* 構造靜態代理構造函數
* 初始化被代理對象
*/
public ProxyStatic()
{
this.proxy = new Proxy();
}
/**
* 構造靜態代理構造函數
* 初始化可接收被代理對象
*/
public ProxyStatic(IProxy proxy)
{
this.proxy = proxy;
}
/**
* 代理方法
*/
@Override
public void talk()
{
System.out.println("This is a static proxy");
this.proxy.talk();
}
}
動態代理:
/*
* 文 件 名: ProxyDynamic.java
* 修 改 人: cKF61853
* 修改時間: 2012-12-12
*/
package cn.fareast.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 動態代理實現(動態代理對象)
*
* @author cKF61853
*/
public class ProxyDynamic implements InvocationHandler
{
/**
* 被代理目標對象
*/
private Object target;
/**
* 創建被代理對象
*/
public Object crateProxy(Object target)
{
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
/**
* 動態代理方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
Object result = null;
System.out.println("This is a dynamic proxy.");
result = method.invoke(this.target, args);
return result;
}
}
main 方法
/*
* 文 件 名: ProxyMain.java
* 修 改 人: cKF61853
* 修改時間: 2012-12-12
*/
package cn.fareast.proxy;
import cn.fareast.proxy.iface.IProxy;
/**
* 代理測試類
*
* @author cKF61853
*/
public class ProxyMain
{
/**
* 靜態代理方法測試
*/
public void staticProxy()
{
ProxyStatic proxyStatic = new ProxyStatic();
proxyStatic.talk();
}
/**
* 動態代理方法測試
*/
public void dynamicProxy()
{
ProxyDynamic proxyDynamic = new ProxyDynamic();
IProxy iproxy = (IProxy) proxyDynamic.crateProxy(new Proxy());
iproxy.talk();
}
public static void main(String[] args)
{
ProxyMain main = new ProxyMain();
main.staticProxy();
main.dynamicProxy();
}
}
控制檯輸出
This is a static proxyI can speak, because I'm a person.
This is a dynamic proxy.
I can speak, because I'm a person.