代理模式-你不并知道我的存在
來源:程序員人生 發布時間:2014-11-08 08:08:17 閱讀次數:2296次
代理模式是對象的結構型模式,代理模式給某1個對象提供了1個代理對象,并由代理對象控制對原對象的援用。它的特點代理類與目標類有一樣的接口,并且代理類與目標類之間通常存在關聯關系。含有目標類的援用。以致于代理類能夠控制目標對象,替它完成它的方法:預處理消息、過濾消息、把消息轉發給目標類,和事后處理消息等。
依照代理的創建時期,代理類可以分為兩種:
靜態代理:
UserManager接口:
public interface UserManager {
public void addUser(String userId, String userName); //添加用戶方法
public String findUser(String userId); //刪除用戶方法
}
UserManagerImpl類:
public class UserManagerImpl implements UserManager {
//用戶添加
public void addUser(String userId, String userName) {
try {
System.out.println("用戶ID" + userId);
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
//用戶查詢
public String findUser(String userId) {
System.out.println("用戶ID" + userId);
return "張3";
}
UserManagerImplProxy代理類:
private UserManager userManager; //含有目標類對象的援用
public UserManagerImplProxy(UserManager userManager) {
this.userManager = userManager;
}
public void addUser(String userId, String userName) {
try {
System.out.println("開始添加-->>添加用戶ID" + userId);
userManager.addUser(userId, userName);
System.out.println("成功添加-->>addUser()");
}catch(Exception e) {
e.printStackTrace();
System.out.println("添加失敗-->>addUser()");
}
}
public String findUser(String userId) {
return null; //此處不實現,若是實現,其方式同add方法
}
客戶端調用:
public class Client {
public static void main(String[] args) {
UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());
userManager.addUser("0001", "張3");
}
}
視察以上代碼,可以發現每個代理類只能為1個接口服務(public UserManagerImplProxy(UserManageruserManager))。這樣1來需要建立大量的代理類。并且,所有的代理操作除調用的方法不1樣以外,其他的操作都1樣。例如,findUser中若是實現,將重復使用System.out.println("開始添加-->>添加用戶ID"+
userId); System.out.println("成功添加-->>addUser()"); System.out.println("添加失敗-->>addUser()");重復的代碼出現屢次對開發人員來講是絕對不允許的,那末該怎樣解決這個問題呢?最好的辦法那就是通過1個代理類完玉成部的代理功能,這就觸及到了動態代理。
動態代理:在程序運行時,應用反射機制動態創建而成。
代碼示例:
UserManager接口:
public interface UserManager {
public void addUser(String userId, String userName);
public String findUser(String userId);
}
真正實現類:
public class UserManagerImpl implements UserManager {
public void addUser(String userId, String userName) {
try {
System.out.println("用戶ID" + userId);
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
public String findUser(String userId) {
System.out.println("用戶ID" + userId);
return "張3";
}
動態代理代理類:
public class LogHandler implements InvocationHandler {
private Object targetObject;
//根據傳過來的對象生成代理
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this); //
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start-->>" + method.getName());
for (int i=0; i<args.length; i++) {
System.out.println(args[i]);
}
Object ret = null;
try {
//調用目標方法
ret = method.invoke(targetObject, args);
System.out.println("success-->>" + method.getName());
}catch(Exception e) {
e.printStackTrace();
System.out.println("error-->>" + method.getName());
throw e;
}
return ret;
}
}
動態代理包括1個接口和1個類:
InvocationHandler接口:
Public static Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocatiocHandler h)
throws IllegalArgumentException
返回1個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用途理程序。
參數:
Loader:定義代理類的類加載器
Class<?>[]interfaces:得到全部的接口
InvocationHandlerh:得到InvocationHandler接口的子類實例
Proxy類:動態的聲明出1個代理對象,為何樣生成出代理呢?這個類必須實現了接口才行。如果這個類沒有實現接口,不能生成代理。說白了他就是根據這個接口在內存中建立出1個類。
客戶端調用:
public class Client {
public static void main(String[] args) {
LogHandler logHandler = new LogHandler();
UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl());
userManager.addUser("001","豬豬");
}
}
總結:
動態代理相對靜態代理來講更加靈活了,為何呢?例如重載和覆蓋,重載屬于靜態的結構。當定義兩個參數不1樣的method方法時,我們在調用的時候,需要指定method方法的參數。也就是我們在編譯的時候就指定好該調誰了。而覆蓋的功能更強,由于它的方法調用不是靜態的時候進行綁定,也不是說我寫代碼編譯的時候就指定好我應當調誰。而是在運行的時候決定它是甚么類型就調誰。
正常情況下,我們需要創建很多的代理類,如果我還有其他的manager也需要完成這些功能,那末她還需要創建代理類,來完成。動態代理則不用,由于這個proxySubject這個類不需要自己創建,他在內存中創建。所以你壓根就不知道代理類的存在,固然代理類的個數,也不需要你關心。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈