一、背景
當我們系統中每個方法都需要相同的功能時,比如日誌、事務……;我們之前一直就是將相應都重新寫一遍。如果我們共同的方法出現了問題,所有用到它的方法都必須進行修改,系統維護起來困難,並且不符合OCP原則。那該怎樣去做?
常規編程:重複代碼寫到每個方法中
二、學習軌跡
第一次學習:設計模式(九)-代理模式(結構型) 懵懂中繼續學習,理解的比較淺顯
第二次學習:重溫設計模式(一)—代理模式 現在看來有些理解的或是淺顯,或是真的錯了;但沒之前的糊里糊塗,哪有現在的清晰思路
第三次學習:項目實戰(二)—代理模式 結合項目發現了原來代理是這麼回事,瞭解了動態代理是AOP的實現原理,其中invoke相當於filter(統一進行控制)
三、定義
代理模式給某個對象提供了一個代理對象,並由代理對象控制對原有對象的引用
注:
客戶端不再操作真實對象,直接與代理交互
代理與真實對象接口一致,代理類控制真實對象的訪問
實例:
廠家、代理商、客戶(代理商只負責賣東西,不負責生產)
四、靜態代理
將相同代碼轉移到代理上,易維護,不需要修改真實對象(代理類進行控制)
調用過程:
2、優缺點:
優點:將相同代碼轉移到代理上,修改共同代碼時,不需要修改真實對象,複合OCP原則;系統更加靈活
缺點:未解決代碼重複問題,代理上每個方法依舊有相同代碼
3、代碼實例
/**
* 接口UserManager
*@author 高曉青
* @date 創建時間:2015-3-6 下午8:09:33
*/
public interface UserManager {
public void addUser(String userId,String userName);
public void delUser(String userId);
public String ModifyUser(String userId,String userName);
public void findUser(String userId);
}
(2)具體實現累
package com.bjpowernode.pattern;
/**
*
*@author 高曉青
* @date 創建時間:2015-3-6 下午8:11:55
*/
public class UserManagerImpl implements UserManager {
public void addUser(String userId, String userName) {
System.out.println("UserManagerImpl.addUser() userId-->"+userId);
}
public void delUser(String userId) {
System.out.println("UserManagerImpl.delUser() userId-->"+userId);
}
public String ModifyUser(String userId, String userName) {
System.out.println("UserManagerImpl.ModifyUser() userId-->"+userId);
return "張三";
}
public void findUser(String userId) {
System.out.println("UserManagerImpl.findUser() userId-->"+userId);
}
}
(3)代理類
package com.bjpowernode.pattern;
/**
* 代理類
*@author 高曉青
* @date 創建時間:2015-3-6 下午8:21:34
*/
public class UserManagerImplProxy implements UserManager {
private UserManager userManager;
//對真實對象的引用
public UserManagerImplProxy(UserManager userManager) {
this.userManager=userManager;
}
public void addUser(String userId, String userName) {
try {
//重複的代碼
System.out.println("Start-->>addUser() useId-->>"+userId );
//調用真實對象的方法
userManager.addUser(userId, userName);
//重複的代碼
System.out.println("success-->>addUser()");
} catch (Exception e) {
e.printStackTrace();
//重複的代碼
System.out.println("error-->>addUser()");
}
}
public void delUser(String userId) {
// TODO Auto-generated method stub
}
public String ModifyUser(String userId, String userName) {
// TODO Auto-generated method stub
return null;
}
public void findUser(String userId) {
// TODO Auto-generated method stub
}
}
(4)客戶端
package com.bjpowernode.pattern;
public class Client {
/**
* 客戶端
* @param args
*/
public static void main(String[] args) {
//客戶端只與代理聯繫
UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());
userManager.addUser("0001", "張三");
}
}
五、動態代理
解決了代碼重複問題
前提:代理類與普通類實現相同的接口
1、優缺點
優點:消除了重複代碼
不足:使用了反射,損耗效率
2、代碼實例
JDK動態代理只能對實現了接口的類進行代理,採用JDK動態代理必須實現InvocationHanlder接口,採用Proxy類創建相應的代理類
<1 invoke方法:在代理實例上處理方法調用並返回結果
public Object invoke(Object proxy, Method method,Object[] arguments)
Extract the appropriate property value from the eventand pass it to the action associated with this EventHandler.
<2 Proxy類:用來創建冬天代理類和實例的靜態方法,會根據接口在內存中建立類
<span style="font-family:KaiTi_GB2312;font-size:14px;"><span style="background-color: rgb(255, 255, 255);"> </span></span><pre name="code" class="csharp">(1)接口UserManager
package com.bjpowernode.pattern;
/**
* 接口UserManager
*@author 高曉青
* @date 創建時間:2015-3-6 下午8:09:33
*/
public interface UserManager {
public void addUser(String userId,String userName);
public void delUser(String userId);
public String ModifyUser(String userId,String userName);
public void findUser(String userId);
}
(2)具體實現累
package com.bjpowernode.pattern;
/**
*
*@author 高曉青
* @date 創建時間:2015-3-6 下午8:11:55
*/
public class UserManagerImpl implements UserManager {
public void addUser(String userId, String userName) {
System.out.println("UserManagerImpl.addUser() userId-->"+userId);
}
public void delUser(String userId) {
System.out.println("UserManagerImpl.delUser() userId-->"+userId);
}
public String ModifyUser(String userId, String userName) {
System.out.println("UserManagerImpl.ModifyUser() userId-->"+userId);
return "張三";
}
public void findUser(String userId) {
System.out.println("UserManagerImpl.findUser() userId-->"+userId);
}
}
(3)代理類
package com.bjpowernode.pattern;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogHandler implements InvocationHandler {
private Object targetObject;
//對誰生成代理,將相應的目標傳入,返回Object
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
//根據傳入對象,生成代理對象
//getClassLoader()與目標使用加載器一致
//interface獲得對象實現的接口,根據接口創建代理類,但方法爲空
//this:實現invocationhandler類,指現在這個類
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
<span style="white-space:pre"> </span> 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;
}
}
(4)客戶端
package com.bjpowernode.pattern;
/**
*
*@author 高曉青
* @date 創建時間:2015-3-6 下午8:15:25
*/
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
LogHanlder logHanlder=new LogHanlder();
UserManager userManager=(UserManager)logHanlder.newProxyInstance(new UserManagerImpl());
//調用代理上的方法(內存中)調用invoke方法
userManager.addUser("0001", "張三");
}
}