代理模式:給某一對(duì)象提供代理對(duì)象,并由代理對(duì)象控制具體對(duì)象的引用.
代理,指的就是一個(gè)角色代表另一個(gè)角色采取行動(dòng),就象生活中,一個(gè)紅酒廠商,是不會(huì)直接把紅酒零售客戶的,都是通過代理來完成他的銷售業(yè)務(wù)的.而客戶,也不用為了喝紅酒而到處找工廠,他只要找到廠商在當(dāng)?shù)氐拇砭托辛?具體紅酒工廠在那里,客戶不用關(guān)心,代理會(huì)幫他處理.
代理模式涉及的角色: 1:抽象主題角色.聲明了代理主題和真實(shí)主題的公共接口,使任何需要真實(shí)主題的地方都能用代理主題代替.
2:代理主題角色.含有真實(shí)主題的引用,從而可以在任何時(shí)候操作真實(shí)主題,代理主題功過提供和真實(shí)主題相同的接口,使它可以隨時(shí)代替真實(shí)主題.代理主題通過持有真實(shí)主題的引用,不但可以控制真實(shí)主題的創(chuàng)建或刪除,可以在真實(shí)主題被調(diào)用前進(jìn)行攔截,或在調(diào)用后進(jìn)行某些操作.
3:真實(shí)代理對(duì)象.定義了代理角色所代表的具體對(duì)象.
下面是代理模式的實(shí)現(xiàn)類圖:
根據(jù)上圖的關(guān)系,我們可以用客戶買紅酒來模擬代理模式的實(shí)現(xiàn),
紅酒代理商和紅酒廠商都有銷售紅酒的只能,我們可以為他們定義一個(gè)共同的抽象主題角色,
-
-
-
- public interface SellInterface{
- public Object sell();
- }
/***抽象主題角色,定義了真實(shí)角色和代理角色的公共接口*/public interface SellInterface{public Object sell();}
接著,我們定義真實(shí)主題角色(這里就是紅酒工廠),它必須實(shí)現(xiàn)了SellInterface接口的.
-
-
-
- public class RedWineFactory implements SellInterface{
- public Object sell(){
- System.out.println("真實(shí)主題角色RedWineFactory 被調(diào)用了");
- return new Object();
- }
- }
/***真實(shí)主題角色,這里指紅酒工廠角色,它實(shí)現(xiàn)了SellInterface接口*/public class RedWineFactory implements SellInterface{public Object sell(){System.out.println("真實(shí)主題角色RedWineFactory 被調(diào)用了");return new Object();}}
下面是代理主題角色(這里指紅酒代理商),同樣,代理主題也必須實(shí)現(xiàn)SellInterface接口.
-
-
-
-
- public class RedWineProxy implements SellInterface{
-
- private RedWineFactory redWineFactory;
-
-
- private static int sell_count = 0;
-
- public Object sell(){
- if(checkUser()){
- Object obj = redWineFactory.sell();
- count ++;
- return obj ;
- }else{
- throw new RuntimeException();
- }
- }
-
- protected boolean checkUser(){
-
- return true;
- }
- }
/***代理主題角色,這里指紅酒代理商.它除了也要實(shí)現(xiàn)了sellInterface接口外,還持有紅酒*廠商RedWineFactory 對(duì)象的引用,從而使它能在調(diào)用真實(shí)主題前后做一些必要處理.*/public class RedWineProxy implements SellInterface{//持有一個(gè)RedWineFactory對(duì)象的引用private RedWineFactory redWineFactory;//銷售總量private static int sell_count = 0;public Object sell(){if(checkUser()){//在通過代理主題角色,我們可以在真實(shí)主題角色被調(diào)用前做一些諸如權(quán)限判斷的事情Object obj = redWineFactory.sell();count ++;//同樣,在調(diào)用后我們也可以執(zhí)行一些額外的動(dòng)作.return obj ;}else{throw new RuntimeException();}}protected boolean checkUser(){//do somethingreturn true;}}
接下來看看調(diào)用代理對(duì)象的代碼
- public static void main(String agr[])
- {
- SellInterface sell = new RedWineProxy();
- sell.sell();
- }
public static void main(String agr[]){SellInterface sell = new RedWineProxy();sell.sell();}
從上面的例子可以看出代理模式的工作方式,首先,因?yàn)榇碇黝}和真實(shí)主題都實(shí)現(xiàn)了共同的接口,這使我們可以在不改變?cè)瓉斫涌诘那闆r下,只要用真實(shí)主題對(duì)象的地方,都可以用代理主題來代替.其次,代理主題在客戶和真實(shí)主題之間起了一個(gè)中介作用,利用這個(gè)中介平臺(tái),我們可以在把客戶請(qǐng)求傳遞給真實(shí)主題之前,做一些必要的預(yù)處理.
java對(duì)代理模式的支持 ---動(dòng)態(tài)代理 上面的代理,我們強(qiáng)迫代理類RedWineProxy實(shí)現(xiàn)了抽象接口SellInterface.這導(dǎo)致我們的代理類無法通用于其他接口,所以不得不為每一個(gè)接口實(shí)現(xiàn)一個(gè)代理類.幸好,java為代理模式提供了支持.
java主要是通過Proxy類和InvocationHandler接口來給實(shí)現(xiàn)對(duì)代理模式的支持的.
下面用java的代理機(jī)制來實(shí)現(xiàn)上面的例子
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
-
-
-
- public class ProxyObject implements InvocationHandler{
- private Object proxy_obj;
-
- ProxyObject(Object obj){
- this.proxy_obj = obj;
- }
-
- public static Object factory(Object obj){
- Class cls = obj.getClass();
-
- return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),new ProxyObject(obj));
- }
-
-
-
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- System.out.println("函數(shù)調(diào)用前被攔截了: " + method);
- if(args != null){
-
- System.out.println("方法有 " + args.length + " 個(gè)參數(shù)");
- for(int i = 0; i < args.length; i ++){
- System.out.println(args[i]);
- }
- }
-
- Object mo = method.invoke(proxy_obj, args);
- System.out.println("函數(shù)調(diào)用后進(jìn)行處理 : " + method);
- return mo;
- }
-
-
- public static void main(String agr[]){
- SellInterface si = (SellInterface)factory(new RedWineFactory());
- si.sell();
- }
- }
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/***代理類一定要實(shí)現(xiàn)了InvocationHandler接口*/public class ProxyObject implements InvocationHandler{private Object proxy_obj;ProxyObject(Object obj){this.proxy_obj = obj;}public static Object factory(Object obj){Class cls = obj.getClass();//通過Proxy類的newProxyInstance方法來返回代理對(duì)象return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),new ProxyObject(obj));}/***實(shí)現(xiàn)InvocationHandler接口的invoke*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("函數(shù)調(diào)用前被攔截了: " + method);if(args != null){//打印參數(shù)列表System.out.println("方法有 " + args.length + " 個(gè)參數(shù)");for(int i = 0; i < args.length; i ++){System.out.println(args[i]);}}//利用反射機(jī)制動(dòng)態(tài)調(diào)用原對(duì)象的方法Object mo = method.invoke(proxy_obj, args);System.out.println("函數(shù)調(diào)用后進(jìn)行處理 : " + method);return mo;}//測(cè)試代碼public static void main(String agr[]){SellInterface si = (SellInterface)factory(new RedWineFactory());si.sell();}}
通過上面的代碼可以看出,代理主題ProxyObject類并沒有實(shí)現(xiàn)我們定義的SellInterface借口,
而是實(shí)現(xiàn)了java的InvocationHandler接口,這樣就把代理主題角色和我們的業(yè)務(wù)代碼分離開來,使代理對(duì)象能通用于其他接口.
其實(shí)InvocationHandler接口就是一種攔截機(jī)制,當(dāng)系統(tǒng)中有了代理對(duì)象以后,對(duì)原對(duì)象(真實(shí)主題)方法的調(diào)用,都會(huì)轉(zhuǎn)由InvocationHandler接口來處理,并把方法信息以參數(shù)的形式傳遞給invoke方法,這樣,我們就可以在invoke方法中攔截原對(duì)象的調(diào)用,并通過反射機(jī)制來動(dòng)態(tài)調(diào)用原對(duì)象的方法.這好象也是spring aop編程的基礎(chǔ)吧
接著,用代理模式實(shí)現(xiàn)一個(gè)超級(jí)簡(jiǎn)單的aop攔截機(jī)制 這個(gè)例子可以攔截我們指定的函數(shù),并在攔截前后根據(jù)需要進(jìn)行處理
-
-
-
- public interface AopInterface {
- public void before(Object obj);
- public void end(Object obj);
- }
/***切面接口,通過實(shí)現(xiàn)這個(gè)接口,我們可以對(duì)指定函數(shù)在調(diào)用前后進(jìn)行處理*/public interface AopInterface {public void before(Object obj);//調(diào)用的處理public void end(Object obj);//調(diào)用后的處理}
這個(gè)是實(shí)現(xiàn)了AopInterface 接口,在這里我們實(shí)現(xiàn)了我們的處理邏輯
- public class AopInterfaceImp implements AopInterface{
-
- public void before(Object obj) {
- System.out.println("調(diào)用前攔截");
- }
-
- public void end(Object obj) {
- System.out.println("調(diào)用調(diào)用后處理");
- }
-
- }
public class AopInterfaceImp implements AopInterface{public void before(Object obj) {System.out.println("調(diào)用前攔截");}public void end(Object obj) {System.out.println("調(diào)用調(diào)用后處理");}}
接著是代理類
- public class PeoxyObject implements InvocationHandler {
- private AopInterface aop;
- private Object proxy_obj;
- private String methodName;
-
- PeoxyObject(){}
-
- public Object factory(Object obj){
- proxy_obj = obj;
- Class cls = obj.getClass();
- return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),this);
- }
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if(this.aop == null)throw new NullPointerException("aop is null");
- if(method == null)throw new NullPointerException("method is null");
-
- Object o;
-
-
- if(methodName != null && method.toString().indexOf(methodName) != -1){
- aop.before(proxy_obj);
- o = method.invoke(proxy_obj, args);
- aop.end(proxy_obj);
- }else{
-
- o = method.invoke(proxy_obj, args);
- }
- return o;
- }
-
- public AopInterface getAop() {
- return aop;
- }
-
- public void setAop(AopInterface aop) {
- this.aop = aop;
- }
-
- public String getMethodName() {
- return methodName;
- }
-
- public void setMethodName(String methodName) {
- this.methodName = methodName;
- }
- }
public class PeoxyObject implements InvocationHandler {private AopInterface aop;//定義了切入時(shí)調(diào)用的方法private Object proxy_obj;private String methodName;//指定要切入的方法名PeoxyObject(){}public Object factory(Object obj){proxy_obj = obj;Class cls = obj.getClass();return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if(this.aop == null)throw new NullPointerException("aop is null");if(method == null)throw new NullPointerException("method is null");Object o;//如果指定了要攔截方法名,并且調(diào)用的方法和指定的方法名相同,則進(jìn)行攔截處理//否則當(dāng)正常方法處理if(methodName != null && method.toString().indexOf(methodName) != -1){aop.before(proxy_obj);//指定方法調(diào)用前的處理o = method.invoke(proxy_obj, args);aop.end(proxy_obj);//指定方法調(diào)用后的處理}else{//沒有指定的方法,以正常方法調(diào)用o = method.invoke(proxy_obj, args);}return o;}public AopInterface getAop() {return aop;}public void setAop(AopInterface aop) {this.aop = aop;}public String getMethodName() {return methodName;}public void setMethodName(String methodName) {this.methodName = methodName;}}
這里定義一個(gè)用來測(cè)試用的類
- public interface SubInterface {
- public void add(String value1,String value2);
- public void acc(String value1);
- }
-
- public class ImpObject implements SubInterface{
-
- public void add(String value1,String value2) {
- System.out.println("ImpObject add(String value1,String value2)");
- }
-
- public void acc(String value1){
- System.out.println("ImpObject acc(String value1)");
- }
-
- }
public interface SubInterface {public void add(String value1,String value2);public void acc(String value1);}public class ImpObject implements SubInterface{public void add(String value1,String value2) {System.out.println("ImpObject add(String value1,String value2)");}public void acc(String value1){System.out.println("ImpObject acc(String value1)");}}
這里是測(cè)試代碼
- public static void main(String agr[]){
- PeoxyObject po = new PeoxyObject();
-
- po.setAop(new AopInterfaceImp());
- po.setMethodName("acc");
-
- SubInterface si = (SubInterface)po.factory(new ImpObject());
-
- si.add("tt","dd");
-
-
-
- si.acc("tt");
- }
public static void main(String agr[]){PeoxyObject po = new PeoxyObject();po.setAop(new AopInterfaceImp());//我們實(shí)現(xiàn)的攔截處理對(duì)象po.setMethodName("acc");//指定要攔截的函數(shù)SubInterface si = (SubInterface)po.factory(new ImpObject());//因?yàn)閍dd方法不是我們指定的攔截函數(shù),AopInterfaceImp是不會(huì)被執(zhí)行si.add("tt","dd");//acc是我們指定的攔截方法,所以調(diào)用acc的前后會(huì)先執(zhí)行AopInterfaceImp//對(duì)象的兩個(gè)方法si.acc("tt");}
通過上面可以看出,攔截機(jī)制是代理模式的重要使用方式之一,
除了攔截,代理模式還常用于資源加載,當(dāng)我們要加載的資源很大時(shí),我們可以讓真實(shí)主題角色在后臺(tái)加載資源,讓代理主題角色負(fù)責(zé)處理前臺(tái)的等待提示信息.
還有就是授權(quán)機(jī)制,通過代理能攔截真實(shí)主題的能力,來控制真實(shí)主題的訪問權(quán)限.