這篇文章主要為大家詳細介紹了Java代理模式的相關資料,具有一定的參考價值,有興趣的小夥伴們可以參考一下
代理模式是我們比較常用的設計模式之一。其中新想法是為了提供額外的處理或不同的操作而在實際物件與呼叫者之間插入一個代理物件。這些額外的操作通常需要與實際物件進行通信,代理模式一般涉及到的角色有:
抽象角色:聲明真實物件和代理物件的共同介面;
#代理角色:代理對象角色內部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的接口以便在任何時刻都能代替真實對象。同時,代理物件可以在執行真實物件操作時,附加其他的操作,相當於對真實物件進行封裝。
真實角色:代理角色所代表的真實對象,是我們最終要引用的對象。
以下以傳送訊息為例來說明一個簡單的代理模式的基本實作:
首先明確目的:有一個訊息,需要把這個訊息發送出去,根據這個目的定義對應介面MessageHandler。需要的附加操作:假設需要驗證訊息的長度不能超過指定長度並且不能為空,並且我們需要統計相關資訊發送到次數,超過指定的次數我們需要輸出警報。我們透過代理模式來實現這個附加的操作。以下為對應的類別關係圖及範例程式碼。
//接口定义 public interface MessageHandler { public void sendMessage(String msg); } //通过Email方式发送消息的实现类 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; } } //调用类 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
在範例中我們可以方便的在訊息傳送過程中加入各種需要的附加處理方式,也能方便的替換訊息的處理方式,如將透過Email發送訊息替換為透過簡訊發送訊息,而呼叫方不會有絲毫察覺!在任何你想要將一些額外操作分離到具體對象之外,特別是希望能夠很容易做出修改,或者想在具體對象的方法執行前插入一些額外操作的時候,代理就顯得十分有用!
動態代理
Java中動態代理機制的引入使得代理模式的想法更加完善與進步,它允許動態的創建代理並支援對動態的對所代理的方法進行呼叫。 Java動態代理類別位於Java.lang.reflect套件下,一般主要涉及以下兩個類別:
(1). Interface InvocationHandler:此介面中僅定義了一個方法Object:invoke(Object obj,Method method, Object[] args)。在實際使用時,第一個參數obj一般是指代理類,method是被代理的方法,如上例中的request(),args為該方法的參數數組。這個抽象方法在代理類別中動態實作。
(2).Proxy:該類即為動態代理類,作用類似於上例中的ProxySubject,其中主要包含以下內容:
Protected Proxy(InvocationHandler h):建構子,估計用於給內部的h賦值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):取得一個代理類,其中loader是類別裝載器,interfaces是真實類別所擁有的全部介面的陣列。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):傳回代理類別的一個實例,傳回後的代理類別可以當作被代理類別使用(可使用被代理類別的在Subject介面中聲明過的方法)。
所謂Dynamic Proxy是這樣一種class:它是在運行時產生的class,在生成它時你必須提供一組interface給它,然後該class就宣稱它實現了這些interface 。你當然可以把該class的實例當作這些interface中的任何一個來用。當然啦,這個Dynamic Proxy其實就是一個Proxy,它不會為你做實質的工作,在產生它的實例時你必須提供一個handler,由它接手實際的工作。 下面我們透過動態代理重新實作上面發送訊息的範例!
在上面的範例基礎上,我們先加入一個透過簡訊來傳送訊息的處理類別:
public class SmsMessage implements MessageHandler { @Override public void sendMessage(String msg) { // TODO Auto-generated method stub System.out.println("SMS Message :" + msg+" sent !"); } } //动态代理类 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; } } //下面是调用 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 !
以上例子中,通过调用Proxy.newProxyInstance方法创建动态代理对象,该方法需要传入一个 类加载器、一组希望代理实现的接口列表、InvocationHandler 接口的一个具体实现。动态代理可以将所有调用重定向到调用处理器,通常我们会向该处理器传递一个时间对象的引用。invoke()方法中传递进来了代理对象,当你需要区分请求来源时这是非常有用的,例如你可以通过判断传入的方法名屏蔽掉某些方法的执行!动态代理机制并不是会很频繁使用的方法,它通常用来解决一些特定情况下的问题,因此不要盲目的为了使用而使用,要根据自己的实际需求来决定!
以上是Java代理模式詳細解析(圖文)的詳細內容。更多資訊請關注PHP中文網其他相關文章!