您好,登錄后才能下訂單哦!
1.代理模式概述
為什么要有“代理”? 生活中就有很多例子,例如委托業務等等,代理就是被代理者沒有能力或者不愿意去完成某件事情,需要找個人代替自己去完成這件事,這才是“代理”存在的原因。例如,我現在需要出國,但是我不愿意自己去辦簽證、預定機票和酒店(覺得麻煩 ,那么就可以找旅行社去幫我辦,這時候旅行社就是代理,而我自己就是被代理了。
代理模式的定義:ProxyPattern(即:代理模式),23種常用的面向對象軟件的設計模式之一為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。
2.靜態代理
以下我們借用JinLian和XiMen的例子來介紹一下靜態代理
2.1不使用代理模式時
JinLian類的內部有一個happy方法,此時如果我們的XiMen類如果想要使用這個方法,正常情況下直接創建一個JinLian類調用happy方法即可
public class JinLian{
public void happy() {
System.out.println("金蓮happy...");
}
}
public class XiMen {
public static void main(String[] args) {
JinLian jinLian =new JinLian();
jinLian.happy();
}
}
2.2使用靜態代理
如果我們使用靜態代理模式的話,XiMen類如果想要調用happy方法,那么它便不會直接去找JinLian類,而是通過一個代理對象WangPo間接找到JinLian類。這樣做的好處是,我們可以通過WangPo這個代理,在happy方法中添加一些想要的功能,例如:
public class WangPo {
JinLian jinLian ;
public WangPo(JinLian jinLian) {
this.jinLian = jinLian;
}
public void happy(){
openHouse();
jinLian.happy();
clear();
}
public void clear(){
System.out.println("打掃戰場...");
}
public void openHouse(){
System.out.println("以做衣服的名義把2人約到房間...");
}
}//WangPo
public class XiMen {
public static void main(String[] args) {
JinLian jinLian =new JinLian();
WangPo wangPo =new WangPo(jinLian);
wangPo.happy();
}
}//XiMen
public class JinLian {
public void happy() {
System.out.println("金蓮happy...");
}
}//JinLian
這樣,XiMen類想要調用happy方法,并且想要使用新增的功能時,只需要調用WangPo的happy方法即可。
2.3靜態代理改進
現在,雖然實現了代理模式,但是目前的代理對象和委托對象都已經固定了,這樣做局限性很大,我們的XiMen類如果想要調用其它委托者的Happy方法,就只能找其它的代理對象,此時我們對代碼再次改進一下,新加一個FindHappy接口,委托者對象只需要實現FinHappy接口,便可以實現一個代理對象代理多個委托對象。如果,XiMen現在想要通過WangPo使用JinLian和YanPoXi的happy方法。我們可以做出如下改寫
public interface FindHappy {// 抽象角色
void happy();
}
public class JinLian implements FindHappy {//委托者1
@Override
public void happy() {
System.out.println("金蓮happy...");
}
}//JinLian
public class YanPoXi implements FindHappy {//委托者2
@Override
public void happy() {
System.out.println("閻婆惜happy...");
}
}//YanPoXi
public class WangPo implements FindHappy {//代理者
FindHappy findHappy;
public WangPo(FindHappy findHappy) {
this.findHappy = findHappy;
}
public void openHouse(){
System.out.println("以做衣服的名義把2人約到房間...");
}
@Override
public void happy() {
openHouse();
// 讓委托者happy()
findHappy.happy();
clear();
}
public void clear(){
System.out.println("打掃戰場...");
}
}
public class XiMen {
public static void main(String[] args) {
JinLian jinLian = new JinLian();
YanPoXi yanPoXi = new YanPoXi();
WangPo wangPo = new WangPo(yanPoXi);
WangPo wangPo1 =new WangPo(jinLian);
wangPo.happy();
wangPo1.happy();
}
}
如此一來我們便可以通過一個代理對象代理所有重寫了happy方法的對象
這便是靜態代理模式
3.動態代理
動態代理與靜態代理的區別是,動態代理的代理對象是在使用者調用委托者的方法時才創建的,動態代理它可以直接給某一個目標(被代理 對象)對象(實現了某個或者某些接口)生成一個代理對象,也就是當XiMen類想要使用happy方法時,代理對象才會生成,并且不需要代理類存在
3.1動態代理原理
動態代理與代理模式原理是一樣的,只是它沒有具體的代理類,直接通過反射生成了一個代理對象。簡而言之:動態代理就是直接通過反射生成一個代理對象,代理類是不需要存在的鄭州好的婦科醫院 http://www.zzkedayy.com/
3.2動態代理的獲取及使用
jdk提供一個Proxy類可以直接給實現接口類的對象直接生成代理對象
Proxy的API介紹
Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)生成一個代理對象,這個方法的返回值類型是一個Object類型,但是在此方法的第三個參數的匿名內部類中我們重寫了委托者的方法,而委托者又必定實現了FindHappy接口,因此此處我們可以使用向下強轉,并用一個Findhappy接口的對象進行接收
參數1:ClassLoader loader 被代理對象的類加載器, 一般使用被代理對象的類加載器
參數2:Class[] interfaces 被代理對象的要實現的接口 一般使用的被代理對象實現的接口
參數3:InvocationHandler h (接口)(使用匿名內部類直接實現)執行處理類返回值: 代理對象
InvocationHandler中的invoke(Object proxy, Method method, Object[] args)方法:調用代理類的任何方法,此方法都會執行,因此當一個委托對象中有多個方法需要代理時,需要在此匿名內部類中使用反射獲取方法名,判斷是哪個方法在請求代理,一一實現各個方法需要增添的功能
3.1:代理對象(慎用)參數
3.2:當前執行的方法參數
3.3:當前執行的方法運行時傳遞過來的參數返回值:當前方法執行的返回值
public class Demo1 {
public static void main(String[] args) {
// 動態產生一個JinLian類的代理對象 類似生成王婆代理對象
FindHappy proxy = (FindHappy) Proxy.newProxyInstance(JinLian.class.getClassLoader(), JinLian.class.getInterfaces(), new InvocationHandler() {
public void openHouse(){
System.out.println("以做衣服的名義把2人約到房間...");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 但凡是代理對象調用方法,這個invoke方法就會執行
// 參數1proxy:代理對象(慎用),因為代理對象調用方法就會執行invoke,很容易出現遞歸,出現棧內存溢出
// 參數2 method:當前代理對象調用的方法
// 參數3:當前代理對象調用的方法,運行時傳遞過來的參數
// 返回值:當前方法執行的返回值
if(method.getName()=="happy"){
openHouse();
method.invoke(JinLian.class.newInstance());// 類似 jinLian.happy()
clear();
return null;
}
}
public void clear(){
System.out.println("打掃戰場...");
}
});
// 使用代理對象調用方法
proxy.happy();
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。