深入淺析Java的代理模式?相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
成都創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比樺南網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式樺南網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋樺南地區(qū)。費(fèi)用合理售后完善,十多年實(shí)體公司更值得信賴。
代理模式是我們比較常用的設(shè)計(jì)模式之一。其中新思想是為了提供額外的處理或者不同的操作而在實(shí)際對(duì)象與調(diào)用者之間插入一個(gè)代理對(duì)象。這些額外的操作通常需要與實(shí)際對(duì)象進(jìn)行通信,代理模式一般涉及到的角色有:
抽象角色:聲明真實(shí)對(duì)象和代理對(duì)象的共同接口;
代理角色:代理對(duì)象角色內(nèi)部含有對(duì)真實(shí)對(duì)象的引用,從而可以操作真實(shí)對(duì)象,同時(shí)代理對(duì)象提供與真實(shí)對(duì)象相同的接口以便在任何時(shí)刻都能代替真實(shí)對(duì)象。同時(shí),代理對(duì)象可以在執(zhí)行真實(shí)對(duì)象操作時(shí),附加其他的操作,相當(dāng)于對(duì)真實(shí)對(duì)象進(jìn)行封裝。
真實(shí)角色:代理角色所代表的真實(shí)對(duì)象,是我們最終要引用的對(duì)象。
以下以發(fā)送消息為例來說明一個(gè)簡(jiǎn)單的代理模式的基本實(shí)現(xiàn):
首先明確目的:有一條消息,需要把這個(gè)消息發(fā)送出去,根據(jù)這個(gè)目的定義對(duì)應(yīng)接口MessageHandler。需要的附加操作:假設(shè)需要驗(yàn)證消息的長(zhǎng)度不能超過指定長(zhǎng)度并且不能為空,并且我們需要統(tǒng)計(jì)相關(guān)信息發(fā)送到次數(shù),超過指定的次數(shù)我們需要輸出警報(bào)。我們通過代理模式來實(shí)現(xiàn)這個(gè)附加的操作。下面為對(duì)應(yīng)的類關(guān)系圖及示例代碼。
//接口定義 public interface MessageHandler { public void sendMessage(String msg); } //通過Email方式發(fā)送消息的實(shí)現(xiàn)類 public class EmailMessage implements MessageHandler { @Override public void sendMessage(String msg) { // TODO Auto-generated method stub System.out.println(msg+" send!!"); } } //消息處理的代理類 public class MessageProxy implements MessageHandler { private static int count; private MessageHandler emailMsg; @Override public void sendMessage(String msg) { // TODO Auto-generated method stub if(checkMessage(msg)) { if(emailMsg==null) emailMsg=new EmailMessage(); count++; emailMsg.sendMessage(msg); System.out.println("Message sent:"+count); } } private boolean checkMessage(String msg) { return msg != null && msg.length() > 10; } } //調(diào)用類 public class MainClass { private static void runProxy(MessageHandler handler) { handler.sendMessage("message for test"); } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub runProxy(new EmailMessage()); System.out.println("++++++++++++++++Pjroxy++++++++++++++++++"); runProxy(new MessageProxy()); } } //輸出 message for test send!! ++++++++++++++++Pjroxy++++++++++++++++++ message for test send!! Message sent:1
在例子中我們可以方便的在消息發(fā)送過程中添加各種需要的附加處理方式,也能方便的替換消息的處理方式,如將通過Email發(fā)送消息替換為通過短信發(fā)送消息,而調(diào)用方不會(huì)有絲毫察覺!在任何你想要將一些額外操作分離到具體對(duì)象之外,特別是希望能夠很容易做出修改,或者想在具體對(duì)象的方法執(zhí)行前插入一些額外操作的時(shí)候,代理就顯得十分有用!
動(dòng)態(tài)代理
Java中動(dòng)態(tài)代理機(jī)制的引入使得代理模式的思想更加完善與進(jìn)步,它允許動(dòng)態(tài)的創(chuàng)建代理并支持對(duì)動(dòng)態(tài)的對(duì)所代理的方法進(jìn)行調(diào)用。Java動(dòng)態(tài)代理類位于Java.lang.reflect包下,一般主要涉及到以下兩個(gè)類:
(1). Interface InvocationHandler:該接口中僅定義了一個(gè)方法Object:invoke(Object obj,Method method, Object[] args)。在實(shí)際使用時(shí),第一個(gè)參數(shù)obj一般是指代理類,method是被代理的方法,如上例中的request(),args為該方法的參數(shù)數(shù)組。這個(gè)抽象方法在代理類中動(dòng)態(tài)實(shí)現(xiàn)。
(2).Proxy:該類即為動(dòng)態(tài)代理類,作用類似于上例中的ProxySubject,其中主要包含以下內(nèi)容:
Protected Proxy(InvocationHandler h):構(gòu)造函數(shù),估計(jì)用于給內(nèi)部的h賦值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):獲得一個(gè)代理類,其中l(wèi)oader是類裝載器,interfaces是真實(shí)類所擁有的全部接口的數(shù)組。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理類的一個(gè)實(shí)例,返回后的代理類可以當(dāng)作被代理類使用(可使用被代理類的在Subject接口中聲明過的方法)。
所謂Dynamic Proxy是這樣一種class:它是在運(yùn)行時(shí)生成的class,在生成它時(shí)你必須提供一組interface給它,然后該class就宣稱它實(shí)現(xiàn)了這些interface。你當(dāng)然可以把該class的實(shí)例當(dāng)作這些interface中的任何一個(gè)來用。當(dāng)然啦,這個(gè)Dynamic Proxy其實(shí)就是一個(gè)Proxy,它不會(huì)替你作實(shí)質(zhì)性的工作,在生成它的實(shí)例時(shí)你必須提供一個(gè)handler,由它接管實(shí)際的工作。 下面我們通過動(dòng)態(tài)代理來重新實(shí)現(xiàn)上面發(fā)送信息的例子!
在上面的例子基礎(chǔ)上,我們先添加一個(gè)通過短信來發(fā)送消息的處理類:
public class SmsMessage implements MessageHandler { @Override public void sendMessage(String msg) { // TODO Auto-generated method stub System.out.println("SMS Message :" + msg+" sent !"); } } //動(dòng)態(tài)代理類 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicMessageProxy implements InvocationHandler { private static int count; private MessageHandler msgHandler; public DynamicMessageProxy(MessageHandler handler) { msgHandler = handler; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("++++++++=============+++++++++"); System.out.println("proxy:" + proxy.getClass()); System.out.println("method:" + method); System.out.println("++++++++=============+++++++++"); if (args != null && args.length == 1 && checkMessage((String) args[0])) { count++; System.out.println("Message sent:" + count); return method.invoke(msgHandler, args); } return null; } private boolean checkMessage(String msg) { return msg != null && msg.length() > 10; } } //下面是調(diào)用 import java.lang.reflect.Proxy; public class MainClass { private static void runProxy(MessageHandler handler) { handler.sendMessage("message for test"); } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub // runProxy(new EmailMessage()); // System.out.println("++++++++++++++++Proxy++++++++++++++++++"); // runProxy(new MessageProxy()); MessageHandler handler = new EmailMessage(); runProxy(handler); MessageHandler proxy = (MessageHandler) Proxy.newProxyInstance( MessageHandler.class.getClassLoader(), new Class[] { MessageHandler.class }, new DynamicMessageProxy( handler)); runProxy(proxy); System.out.println("++++++++++++++++++++++++++++++++++"); // 短信方式 handler = new SmsMessage(); runProxy(handler); proxy = (MessageHandler) Proxy.newProxyInstance(MessageHandler.class .getClassLoader(), new Class[] { MessageHandler.class }, new DynamicMessageProxy(handler)); runProxy(proxy); } } //下面為以上方法的輸出: message for test send!! ++++++++=============+++++++++ proxy:class $Proxy0 method:public abstract void MessageHandler.sendMessage(java.lang.String) ++++++++=============+++++++++ Message sent:1 message for test send!! ++++++++++++++++++++++++++++++++++ SMS Message :message for test sent ! ++++++++=============+++++++++ proxy:class $Proxy0 method:public abstract void MessageHandler.sendMessage(java.lang.String) ++++++++=============+++++++++ Message sent:2 SMS Message :message for test sent !
以上例子中,通過調(diào)用Proxy.newProxyInstance方法創(chuàng)建動(dòng)態(tài)代理對(duì)象,該方法需要傳入一個(gè) 類加載器、一組希望代理實(shí)現(xiàn)的接口列表、InvocationHandler 接口的一個(gè)具體實(shí)現(xiàn)。動(dòng)態(tài)代理可以將所有調(diào)用重定向到調(diào)用處理器,通常我們會(huì)向該處理器傳遞一個(gè)時(shí)間對(duì)象的引用。invoke()方法中傳遞進(jìn)來了代理對(duì)象,當(dāng)你需要區(qū)分請(qǐng)求來源時(shí)這是非常有用的,例如你可以通過判斷傳入的方法名屏蔽掉某些方法的執(zhí)行!動(dòng)態(tài)代理機(jī)制并不是會(huì)很頻繁使用的方法,它通常用來解決一些特定情況下的問題,因此不要盲目的為了使用而使用,要根據(jù)自己的實(shí)際需求來決定!
看完上述內(nèi)容,你們掌握深入淺析Java的代理模式的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!