生活随笔
收集整理的這篇文章主要介紹了
一天一种设计模式之五-----代理模式
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
一.代理模式簡介
代理模式屬于結構型模式
定義:代理模式為其他對象提供一種代理以控制對這個對象的訪問。
代理模式是java框架層面應用最廣泛的少數幾種設計模式之一,非常重要。
適用場景:
遠程代理,為一個對象在不同的地址空間提供局部代表,這樣可以隱藏一個對象存在于不同地址空間的事實。
虛擬代理,根據需要創建開銷很大的對象,通過它來存放實例化需要很長時間的對象,這樣可以達到性能優化;
安全代理,用來控制真實對象訪問時的權限。一般用于對象應該有不同的訪問權限的時候;
智能指引,是指當調用真實的對象的時候,代理處理另外的一些事情(用的比較多)
代理模式要求代理實現與被代理對象相同的接口(cglib與被代理對象是子類與父類的關系),以保證任何時候都能代替真實對象。這也是它與適配器模式的區別!!
代理模式廣泛應用于aop編程。能夠在不改變源代碼的前提下提供統一的日志管理,前后置攔截器,符合開放封閉原則、依賴倒置原則,
二.測試代碼
????下面代碼屬于靜態代理,大致場景是追求者會追妹子,但他不認識某girl,而通過代理類認識,所以追求者通過代理類對妹子展開了追求。
public?class?ProxyTest?{public?static?void?main(String[]?args)?{PursuitWay?pursuitWay=new?Proxy(new?Pursuiter(new?Girl("小白")));pursuitWay.giveFlower();pursuitWay.giveGift();}
}
interface?PursuitWay{void?giveFlower();void?giveGift();
}
class?Girl{private?String?name;public?Girl(String?name)?{this.name=name;}public?String?getName()?{return?name;}public?void?setName(String?name)?{this.name?=?name;}}
class?Pursuiter?implements?PursuitWay{Girl?girl;public?Pursuiter(Girl?girl){this.girl=girl;}@Overridepublic?void?giveFlower()?{System.out.println("追求者送"+girl.getName()+"花");}@Overridepublic?void?giveGift()?{System.out.println("追求者送"+girl.getName()+"禮物");}}class?Proxy?implements?PursuitWay{PursuitWay?pursuter;public?Proxy(PursuitWay?pursuiter){this.pursuter=pursuiter;}@Overridepublic?void?giveFlower()?{pursuter.giveFlower();}@Overridepublic?void?giveGift()?{pursuter.giveGift();}} 既然是通過代理去追妹子,那每次苦力活代理做做日志,設置個障礙就不難理解了吧。
上述功能如果要通過適配器模式實現,則proxy不必非要實現PursuitWay,它會有自己的方法而不必非要是giveXXX,只需要在它自己的方法中實現pursuter的giveXXX方法就可以了,具體代碼略。
上述代理模式屬于靜態代理,因為代理類是我們自己編寫出來的,而動態代理則是通過java虛擬機,在運行期間生成的字節碼。
下述代碼是通過動態代理實現的相同功能
? 1. ? 獲取追求者上的所有接口列表;
??? 2.?? 確定要生成的代理類的類名,默認為:com.sun.proxy.$ProxyXXXX ;
??? 3.?? 根據需要實現的接口信息,在代碼中動態創建 該Proxy類的字節碼;
??? 4 .? 將對應的字節碼轉換為對應的class 對象;
??? 5.?? 創建InvocationHandler 實例handler,用來處理Proxy所有方法調用;
??? 6.?? Proxy 的class對象 以創建的handler對象為參數,實例化一個proxy對象
public?class?ProxyTest?{public?static?void?main(String[]?args)?{Class?clazz=Proxy.getProxyClass(Pursuiter.class.getClassLoader(),?Pursuiter.class.getInterfaces());System.out.println("proxy類為"+clazz.getName());System.out.println("proxy實現的接口有"+clazz.getInterfaces()[0].getName());System.out.println("-----開始生成代理對象(實際上該代理對象就是一個該接口的實現類)");PursuitWay?pursuter=(PursuitWay)?Proxy.newProxyInstance(Pursuiter.class.getClassLoader(),?Pursuiter.class.getInterfaces(),?new?MyInvocationHandler(new?Pursuiter(new?Girl("小白"))));pursuter.giveFlower();pursuter.giveGift();}
}
interface?PursuitWay{void?giveFlower();void?giveGift();
}
class?Girl{private?String?name;public?Girl(String?name)?{this.name=name;}public?String?getName()?{return?name;}public?void?setName(String?name)?{this.name?=?name;}}
class?Pursuiter?implements?PursuitWay{Girl?girl;public?Pursuiter(Girl?girl){this.girl=girl;}@Overridepublic?void?giveFlower()?{System.out.println("追求者送"+girl.getName()+"花");}@Overridepublic?void?giveGift()?{System.out.println("追求者送"+girl.getName()+"禮物");}}
class?MyInvocationHandler?implements?InvocationHandler{Object?object;public?MyInvocationHandler(Object?object){this.object=object;}@Overridepublic?Object?invoke(Object?proxy,?Method?method,?Object[]?args)throws?Throwable?{return?method.invoke(object,?args);}} 上述代碼通過jdk自帶的代理類實現,它和靜態代理類有同樣的局限性,就是要求被代理類必須有一個或者多個對應具體業務邏輯的接口。myInvocationHandler里邊的invoke方法中可以提供攔截、寫日志等功能。
cglib包的代理類CglibProxy是針對某個類生成一個子類,該子類自然會包括其父類的所有業務邏輯方法。而且不在局限于必須有上層接口。但是cglib包也要求被代理類不能為final類,否則繼承不了,測試代碼和動態代理很像,略。
cglib底層采用ASM字節碼生成框架,使用字節碼技術生成代理類,理論上比使用Java反射效率要高,不過有大神曾經測試過,貌似性能差不多,而且jdk的動態代理還要比cglib效率高一點點。有興趣的朋友可以去試試。
歡迎大神交流意見。
下一節將會講解工廠方法模式,該模式在service層應用很普遍。敬請期待。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
轉載于:https://my.oschina.net/u/2323537/blog/634874
總結
以上是生活随笔為你收集整理的一天一种设计模式之五-----代理模式的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。