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