国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
代理模式、動(dòng)態(tài)代理和面向方面(AOP)
理的意思很好理解,它借鑒了我們?nèi)粘K玫拇淼囊馑迹壕褪潜緛?lái)該自己親自去做的某件事,由于某種原因不能直接做,而只能請(qǐng)人代替你做,這個(gè)被你請(qǐng)來(lái)做事的人就是代理。比如過(guò)春節(jié)要回家,由于你要上班,沒(méi)時(shí)間去買(mǎi)票,就得票務(wù)中介代你購(gòu)買(mǎi),這就是一種代理模式。這個(gè)情景可以形象的描述如下:
class:火車(chē)站
{
        賣(mài)票:
       {……}
}
    火車(chē)站是賣(mài)票的地方,我們假設(shè)只能在火車(chē)站買(mǎi)到票。賣(mài)票的動(dòng)作實(shí)質(zhì)是火車(chē)站類(lèi)完成的。
Class:票務(wù)中介
{
        賣(mài)票:
        {
               收中介費(fèi);
              火車(chē)站.賣(mài)票;
}
}
    顧客找票務(wù)中介買(mǎi)票的時(shí)候,調(diào)用票務(wù)中介.賣(mài)票。票務(wù)中介其實(shí)做了兩件事,一是去火車(chē)站買(mǎi)票,二是不能白幫你賣(mài)票,肯定要收中介費(fèi)。而你得到的好處是不用直接去火車(chē)站買(mǎi)票,節(jié)省了買(mǎi)票的時(shí)間用來(lái)上班。
    以上我們簡(jiǎn)單模擬了代理模式的情景和為什么要使用代理模式,下面我們以一個(gè)例子來(lái)具體分析一下JAVA中的代理模式。
    假設(shè)有一個(gè)信息管理系統(tǒng),用些用戶有瀏覽信息的權(quán)限,有些用戶有瀏覽、添加和修改信息的權(quán)限,還有些用戶有除了上述的權(quán)限,還有刪除信息的權(quán)限,那么我們最容易想到的做法如下:
public class ViewAction
{
        //由userId計(jì)算權(quán)限
        ……
        String permission = ……;
       if(permission.equals(Constants.VIEW))
        {
               System.out.println(“You could view the information……”);
               ……
}
}
    其他的動(dòng)作都和瀏覽信息的動(dòng)作差不多。我們來(lái)看這樣的類(lèi),很容易看出它的一些缺點(diǎn)來(lái):第一、它把權(quán)限計(jì)算和動(dòng)作執(zhí)行都放在一個(gè)類(lèi)里,兩者的功能相互混在一起,容易造成思路的混亂,而且修改維護(hù)和測(cè)試都不好;一句話來(lái)說(shuō),它不滿足單一職責(zé)原則。第二是客戶調(diào)用的時(shí)候依賴具體的類(lèi),造成擴(kuò)展和運(yùn)行期內(nèi)的調(diào)用的困難,不滿足依賴顛倒原則。
    既然有這么多的問(wèn)題,我們有必要對(duì)該類(lèi)進(jìn)行重新設(shè)計(jì)。其實(shí)大家早已想到,這個(gè)類(lèi)應(yīng)該使用代理模式。是啊,和我們買(mǎi)火車(chē)票的動(dòng)作一樣,動(dòng)作類(lèi)不能直接執(zhí)行那個(gè)動(dòng)作,而是要先檢查權(quán)限,然后才能執(zhí)行;先檢查權(quán)限,后執(zhí)行的那各類(lèi)其實(shí)就是一個(gè)代理類(lèi),修改后的代碼如下:
public interface Action
{
        public void doAction();
}
   首先是設(shè)計(jì)一個(gè)接口,用來(lái)滿足依賴顛倒原則。
Public class ViewAction implements Action
{
        public void doAction()
        {
               //做View的動(dòng)作
               System.out.println(“You could view the information……”);
               ……
}
}
    這個(gè)類(lèi)跟火車(chē)站一樣,是動(dòng)作的真實(shí)執(zhí)行者。
Public class ProxyViewAction implements Action
{
        private Action action = new ViewAction();
        public void doAction()
        {
               //調(diào)用權(quán)限類(lèi)的方法取得用戶權(quán)限
               if(Permission.getPermission(userId).equals(Constants.VIEW))
               {
                      action.doAction();
}
}
}
    這是代理類(lèi),很容易理解。在我們的ProxyViewAction類(lèi)中,除了做了客戶真正想要做的動(dòng)作:doAction()以外,還進(jìn)行了額外的動(dòng)作檢查用戶的權(quán)限。而作核心動(dòng)作doAction()是在一個(gè)干干凈凈的類(lèi):ViewAction中進(jìn)行,這個(gè)類(lèi)只做核心動(dòng)作,對(duì)其他的不關(guān)心,滿足了單一職責(zé)原則。
    客戶端通過(guò)調(diào)用代理類(lèi)來(lái)執(zhí)行動(dòng)作,而代理類(lèi)一是將權(quán)限判斷和動(dòng)作的執(zhí)行分離開(kāi)來(lái),滿足了單一職責(zé)原則;二是實(shí)現(xiàn)了一個(gè)接口,從而滿足了依賴顛倒原則。比第一個(gè)思路好了很多。
    代理又被稱為委派,說(shuō)的是代理類(lèi)并不真正的執(zhí)行那個(gè)核心動(dòng)作,而是委派給另外一個(gè)類(lèi)去執(zhí)行,如ProxyView類(lèi)中,ProxyView類(lèi)并沒(méi)有真正執(zhí)行doAction()方法,而是交給ViewAction類(lèi)去執(zhí)行。
    我們?cè)賮?lái)看代理類(lèi)ProxyViewAction,可以看到它不僅依賴于接口Action,而且依賴于具體的實(shí)現(xiàn)ViewAction。這樣對(duì)我們的系統(tǒng)擴(kuò)展很不利,比如我們有Add動(dòng)作、Delete動(dòng)作、Modify動(dòng)作等等,我們需要對(duì)每一個(gè)動(dòng)作都寫(xiě)一個(gè)代理類(lèi),而這些代理類(lèi)都做同樣的事情,先進(jìn)行權(quán)限判斷,然后再委派。所以我們需要對(duì)這些代理再進(jìn)行一次抽象,讓它只依賴接口Action,而不依賴于具體的實(shí)現(xiàn)。
    要實(shí)現(xiàn)這樣的想法,我們需要將代理類(lèi)中的具體實(shí)現(xiàn)提走,讓代理的使用者在運(yùn)行期提供具體的實(shí)現(xiàn)類(lèi),即所謂的依賴注入,如下:
Public class ProxyAction implements Action
{
        private Action action;
        public ProxyAction(Action action)
        {
               this.action = action;
}
        public void doAction()
        {
               //調(diào)用權(quán)限類(lèi)的方法取得用戶權(quán)限
               if(Permission.getPermission(userId).equals(action.getClass().getName()))
               {
                      action.doAction();
}
}
}
    這樣,我們就將所有實(shí)現(xiàn)了Action接口的實(shí)現(xiàn)使用一個(gè)代理類(lèi)來(lái)代理它們。除了ViewAction類(lèi)能用,以后擴(kuò)展的AddAction、       ModifyAction、DeleteAction類(lèi)等等,都可以使用一個(gè)代理類(lèi):ProxyAction。
    而我們的客戶端類(lèi)似如下:
Action action = ProxyAction(new ViewAction);
Action.doAction();
    通過(guò)對(duì)代理類(lèi)的依賴注入,我們使得代理類(lèi)初步有了一定擴(kuò)展性。但是我們還要看到,這個(gè)代理類(lèi)依賴于某一個(gè)確定的接口。這仍然不能滿足我們的實(shí)際要求,如我們的系統(tǒng)的權(quán)限控制一般是整個(gè)系統(tǒng)級(jí)的,這樣系統(tǒng)級(jí)的權(quán)限控制,我們很難在整個(gè)系統(tǒng)里抽象出一個(gè)統(tǒng)一的接口,可能會(huì)有多個(gè)接口,按照上面的代理模式,我們需要對(duì)每一個(gè)接口寫(xiě)一個(gè)代理類(lèi),同樣,這些類(lèi)的功能都是一樣的。這顯然不是一個(gè)好地解決辦法。
    基于上面的原因,我們需要解決一個(gè)系統(tǒng)在沒(méi)有統(tǒng)一的接口的情況下,對(duì)一些零散的對(duì)象的某一些動(dòng)作使用代理模式的問(wèn)題。JAVA API為我們引入了動(dòng)態(tài)代理或動(dòng)態(tài)委派的技術(shù)。
    動(dòng)態(tài)代理的核心是InvocationHandler接口,要使用動(dòng)態(tài)代理就必須實(shí)現(xiàn)該接口。這個(gè)接口的委派任務(wù)是在invoke(Object proxy, Method m, Object[] args)方法里面實(shí)現(xiàn)的:
//在調(diào)用核心功能之前作一些動(dòng)作
……
//調(diào)用核心功能
m.invoke(obj, args);
//在調(diào)用核心功能以后做一些動(dòng)作
……
    我們可以看到動(dòng)態(tài)代理其實(shí)用的是反射機(jī)制來(lái)調(diào)用核心功能的:m.invoke(obj, args);正是這種反射機(jī)制的使用使得我們調(diào)用核心功能更加靈活,而不用依賴于某一個(gè)具體的接口,而是依賴于Object對(duì)象。
    下面我們來(lái)具體看看動(dòng)態(tài)代理或動(dòng)態(tài)委派如何使用:
public class ProxyAction implements InvocationHandler {
private Object action;
public ProxyAction(Object action){
       this.action = action;
}
public static Object getInstance(Object action) {
        return Proxy.newProxyInstance(action.getClass().getClassLoader(),
                  action.getClass().getInterfaces(),new ProxyAction(action));
}
 
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        Object result;
 
       try {
           //在委派之前作動(dòng)作,如權(quán)限判斷等
           System.out.println("before method " + m.getName());
           //進(jìn)行委派
           result = m.invoke(action, args);
       }
       catch (InvocationTargetException e) {
           throw e.getTargetException();
       }
      catch (Exception e) {
           throw new RuntimeException("unexpected invocation exception: "+ e.getMessage());
       }
       finally {
           //在委派之后做動(dòng)作
           System.out.println("after method " + m.getName());
       }
       return result;
}
 
}
 
    這個(gè)代理類(lèi),首先是實(shí)現(xiàn)了InvocationHandler接口;然后在getInstance()方法里得到了代理類(lèi)的實(shí)例;在invoke()方法里實(shí)現(xiàn)代理功能,也很簡(jiǎn)單。
    下面我們來(lái)看客戶端:
Action action = (Action)ProxyAction.getInstance(new ViewAction());
Action.doAction();
    我們可以看到代理類(lèi)對(duì)接口的依賴也轉(zhuǎn)移到了客戶端上,這樣,代理類(lèi)不依賴于某個(gè)接口。對(duì)于同樣的代理類(lèi)ProxyAction,我們也可以有如下的客戶端調(diào)用:
Engine engine = (Engine)ProxyAction.getInstance(new EngineImpl());
Engine.execute();
    只要engineImpl類(lèi)實(shí)現(xiàn)了Engine接口,就可以像上面那樣使用。
    現(xiàn)在我們可以看到,動(dòng)態(tài)代理的確是擁有相當(dāng)?shù)撵`活性。但我們同時(shí)也看到了,這個(gè)代理類(lèi)寫(xiě)起來(lái)比較麻煩,而且也差不多每次都寫(xiě)這樣千篇一律的東西,只有委派前的動(dòng)作和委派后的動(dòng)作在不同的代理里有著不同,其他的東西都需要照寫(xiě)。如果這樣的代理類(lèi)寫(xiě)多了,也會(huì)有一些冗余代理。需要我們進(jìn)一步優(yōu)化,這里我們使用模板方法模式來(lái)對(duì)這個(gè)代理類(lèi)進(jìn)行優(yōu)化,如下:
public abstract class BaseProxy implements InvocationHandler {
private Object obj;
protected BaseProxy(Object obj) {
       this.obj = obj;
}
public static Object getInstance(Object obj,InvocationHandler instance) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),instance);
}
 
public Object invoke(Object proxy, Method m, Object[] args)
               throws Throwable {
        Object result;
 
       try {
           this.doBegin();

           result = m.invoke(obj, args);
       }
      catch (InvocationTargetException e) {
           throw e.getTargetException();
       }
      catch (Exception e) {
           throw new RuntimeException("unexpected invocation exception:+ e.getMessage());
       }
       finally {
           this.doAfter();
       }
       return result;
}
public abstract void doBegin();
public abstract void doAfter();
 
}
    這樣,代理的實(shí)現(xiàn)類(lèi)只需要關(guān)注實(shí)現(xiàn)委派前的動(dòng)作和委派后的動(dòng)作就行,如下:
public class ProxyImpl extends BaseProxy {
protected ProxyImpl(Object o) {
       super(o);
}
public static Object getInstance(Object foo) {
        return getInstance(foo,new ProxyImpl(foo));
}
//委派前的動(dòng)作
public void doBegin() {
       System.out.println("begin doing....haha");
}
//委派后的動(dòng)作
public void doAfter() {
       System.out.println("after doing.....yeah");
}

}
    從上面的代碼,我們可以看出代理實(shí)現(xiàn)類(lèi)的確是簡(jiǎn)單多了,只關(guān)注了委派前和委派后的動(dòng)作,這是我們作為一個(gè)代理真正需要關(guān)心的。
    至此,代理模式和動(dòng)態(tài)代理已經(jīng)告一段落。我們將動(dòng)態(tài)代理引申一點(diǎn)說(shuō)開(kāi)去,來(lái)作為這篇文章的蛇足。
    這個(gè)話題就是面向方面的編程,或者說(shuō)AOP。我們看上面的ProxyImpl類(lèi),它的兩個(gè)方法doBegin()和doAfter(),這是做核心動(dòng)作之前和之后的兩個(gè)截取段。正是這兩個(gè)截取段,卻是我們AOP的基礎(chǔ)。在OOP里,doBegin(),核心動(dòng)作,doAfter()這三個(gè)動(dòng)作在多個(gè)類(lèi)里始終在一起,但他們所要完成的邏輯卻是不同的,如doBegin()可能做的是權(quán)限,在所有的類(lèi)里它都做權(quán)限;而在每個(gè)類(lèi)里核心動(dòng)作卻各不相同;doAfter()可能做的是日志,在所有的類(lèi)里它都做日志。正是因?yàn)樵谒械念?lèi)里,doBegin()或doAfter()都做的是同樣的邏輯,因此我們需要將它們提取出來(lái),單獨(dú)分析、設(shè)計(jì)和編碼,這就是我們的AOP的思想。
    這樣說(shuō)來(lái),我們的動(dòng)態(tài)代理就能作為實(shí)現(xiàn)AOP的基礎(chǔ)了。好了,就說(shuō)這么多,關(guān)于AOP技術(shù),我們可以去關(guān)注關(guān)于這方面的知識(shí)。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
別裝了-第一集:代理模式、動(dòng)態(tài)代理和面向方面 - 別裝了!大家一起來(lái)魯棒啦!-loobong - JavaEye技術(shù)網(wǎng)站
java反射機(jī)制與動(dòng)態(tài)代理(三)
Spring框架與AOP思想的研究與應(yīng)用
Spring框架中的AOP思想動(dòng)態(tài)代理模式
十分鐘理解Java中的動(dòng)態(tài)代理
面向?qū)ο缶幊?中)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服