Calvin's Tech Space

          成于堅忍,毀于浮躁

             :: 首頁 :: 聯系 :: 聚合  :: 管理
           

          代理模式、動態(tài)代理和面向方面

              代理的意思很好理解,它借了我日常所用的代理的意思:就是本來自己自去做的某件事,由于某種原因不能直接做,而只能人代替你做,個被你來做事的人就是代理。比如節(jié)要回家,由于你要上班,沒時間票,就得票中介代你購買就是一種代理模式。個情景可以形象的描述如下:

          class:火

          {

                  票:

                 {……}

          }

              站是票的地方,我只能在火到票。票的實質是火完成的。

          Class:票中介

          {

                  票:

                  {

                         收中介

                        .票;

          }

          }

              客找票中介票的候,調用票中介.票。票中介其做了兩件事,一是去火票,二是不能白幫你票,肯定要收中介。而你得到的好是不用直接去火票,節(jié)省了票的時間用來上班。

              以上我們簡單了代理模式的情景和什么要使用代理模式,下面我以一個例子來具體分析一下JAVA中的代理模式。

              有一個信息管理系,用些用瀏覽信息的限,有些用瀏覽、添加和修改信息的限,有些用有除了上述的限,除信息的限,那么我最容易想到的做法如下:

          public class ViewAction

          {

                  //userId

                  ……

                  String permission = ……;

                 if(permission.equals(Constants.VIEW))

                  {

                         System.out.println(“You could view the information……”);

                         ……

          }

          }

              其他的作都和瀏覽信息的作差不多。我來看這樣,很容易看出它的一些缺點來:第一、它把算和執(zhí)行都放在一個里,兩者的功能相互混在一起,容易造成思路的混亂,而且修改維護測試都不好;一句,它不滿職責。第二是客戶調用的候依具體的,造成展和運行期內的調用的困,不滿足依賴顛倒原

              既然有么多的問題,我有必要對該類進行重新設計。其大家早已想到,類應該使用代理模式。是啊,和我們買票的作一不能直接執(zhí)行那個作,而是要先檢查權限,然后才能執(zhí)行;先檢查權限,后執(zhí)行的那各就是一個代理,修改后的代如下:

          public interface Action

          {

                  public void doAction();

          }

             首先是設計一個接口,用來滿足依賴顛倒原

          Public class ViewAction implements Action

          {

                  public void doAction()

                  {

                         //View

                         System.out.println(“You could view the information……”);

                         ……

          }

          }

              跟火站一,是作的真實執(zhí)行者。

          Public class ProxyViewAction implements Action

          {

                  private Action action = new ViewAction();

                  public void doAction()

                  {

                         //調的方法取得用戶權

                         if(Permission.getPermission(userId).equals(Constants.VIEW))

                         {

                                action.doAction();

          }

          }

          }

              是代理,很容易理解。在我ProxyViewAction中,除了做了客真正想要做的作:doAction()以外,還進行了外的檢查限。而作核心doAction()是在一個干干凈凈ViewAction行,只做核心作,其他的不關心,滿足了職責。

              端通過調用代理執(zhí)作,而代理一是將限判斷和作的執(zhí)行分離開來,滿足了職責;二是實現了一個接口,從而滿足了依賴顛倒原。比第一個思路好了很多。

              代理又被稱委派,的是代理并不真正的執(zhí)行那個核心作,而是委派另外一個執(zhí)行,如ProxyView中,ProxyView并沒有真正執(zhí)doAction()方法,而是交ViewAction執(zhí)行。

              再來看代理ProxyViewAction,可以看到它不于接口Action,而且依于具體的實現ViewAction。這樣對的系統擴展很不利,比如我Add作、Delete作、Modify作等等,我需要每一個作都寫一個代理,而些代理都做同的事情,先限判斷,然后再委派。所以我需要對這些代理再行一次抽象,它只依接口Action,而不依于具體的實現。

              實現這樣的想法,我需要將代理中的具體實現提走,代理的使用者在運行期提供具體的實現類,即所的依注入,如下:

          Public class ProxyAction implements Action

          {

                  private Action action;

                  public ProxyAction(Action action)

                  {

                         this.action = action;

          }

                  public void doAction()

                  {

                         //調的方法取得用戶權

                         if(Permission.getPermission(userId).equals(action.getClass().getName()))

                         {

                                action.doAction();

          }

          }

          }

              這樣,我就將所有實現Action接口的實現使用一個代理來代理它。除了ViewAction能用,以后展的AddAction、       ModifyActionDeleteAction等等,都可以使用一個代理ProxyAction

              而我的客似如下:

          Action action = ProxyAction(new ViewAction);

          Action.doAction();

              過對代理的依注入,我使得代理初步有了一定展性。但是我們還要看到,個代理于某一個確定的接口。仍然不能滿足我實際要求,如我的系限控制一般是整個系統級的,這樣統級限控制,我在整個系里抽象出一個一的接口,可能會有多個接口,按照上面的代理模式,我需要每一個接口寫一個代理,同,的功能都是一的。這顯然不是一個好地解決法。

              基于上面的原因,我需要解決一個系在沒有一的接口的情況下,一些零散的象的某一些作使用代理模式的問題JAVA API引入了動態(tài)代理或動態(tài)委派的技

              動態(tài)代理的核心是InvocationHandler接口,要使用動態(tài)代理就必須實現該接口。個接口的委派任是在invoke(Object proxy, Method m, Object[] args)方法里面實現的:

          //調用核心功能之前作一些

          ……

          //調用核心功能

          m.invoke(obj, args);

          //調用核心功能以后做一些

          ……

              可以看到動態(tài)代理其用的是反射機制來調用核心功能的:m.invoke(obj, args);正是種反射機制的使用使得我們調用核心功能更加靈活,而不用依于某一個具體的接口,而是依Object象。

              下面我來具體看看動態(tài)代理或動態(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 {

                                //在委派之前作作,如限判斷等

                     System.out.println("before method " + m.getName());

                                //行委派

                     result = m.invoke(action, args);

                 } catch (InvocationTargetException e) {

                     throw e.getTargetException();

                 } catch (Exception e) {

                     throw new RuntimeException("unexpected invocation exception: "

                            + e.getMessage());

                 } finally {

                                //在委派之后做

                     System.out.println("after method " + m.getName());

                 }

                 return result;

           

          }

          }

              個代理,首先是實現InvocationHandler接口;然后在getInstance()方法里得到了代理例;在invoke()方法里實現代理功能,也很簡單

              下面我來看客端:

          Action action = (Action)ProxyAction.getInstance(new ViewAction());

          Action.doAction();

              可以看到代理類對接口的依移到了客端上,這樣,代理不依于某個接口。于同的代理ProxyAction,我也可以有如下的客調用:

          Engine engine = (Engine)ProxyAction.getInstance(new EngineImpl());

          Engine.execute();

              只要engineImpl類實現Engine接口,就可以像上面那使用。

              在我可以看到,動態(tài)代理的確是有相當的靈活性。但我也看到了,個代理寫起來比,而且也差不多每次都寫這樣千篇一律的西,只有委派前的作和委派后的作在不同的代理里有著不同,其他的西都需要照寫。如果這樣的代理寫多了,也會有一些冗余代理。需要我們進一步優(yōu)化,里我使用模板方法模式來對這個代理類進優(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 {

                  // TODO Auto-generated method stub

                  Object result;

                 try {

                     System.out.println("before method " + m.getName());

                     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 {

                     System.out.println("after method " + m.getName());

                     this.doAfter();

                 }

                 return result;

           

          }

          public abstract void doBegin();

          public abstract void doAfter();

          }

              這樣,代理的實現類只需要關注實現委派前的作和委派后的作就行,如下:

          public class ProxyImpl extends BaseProxy {

          protected ProxyImpl(Object o)

          {

                 super(o);

          }

          public static Object getInstance(Object foo)

          {

                  return getInstance(foo,new ProxyImpl(foo));

          }

          //委派前的

          public void doBegin() {

                  // TODO Auto-generated method stub

                 System.out.println("begin doing....haha");

          }

          //委派后的

          public void doAfter() {

                  // TODO Auto-generated method stub

                 System.out.println("after doing.....yeah");

          }

          }

              從上面的代,我可以看出代理實現類的確是簡單多了,只關注了委派前和委派后的作,是我一個代理真正需要關心的。

              至此,代理模式和動態(tài)代理已告一段落。我動態(tài)代理引申一點開去,來作為這篇文章的蛇足。

              話題就是面向方面的程,或者AOP。我看上面的ProxyImpl,它的兩個方法doBegin()doAfter(),是做核心作之前和之后的兩個截取段。正是兩個截取段,卻是我AOP的基。在OOP里,doBegin(),核心作,doAfter()三個作在多個里始在一起,但他所要完成的邏輯卻是不同的,如doBegin()可能做的是限,在所有的里它都做限;而在每個里核心作卻各不相同;doAfter()可能做的是日志,在所有的里它都做日志。正是因在所有的里,doBegin()doAfter()都做的是同邏輯,因此我需要將它提取出來,獨分析、設計編碼就是我AOP的思想。

              這樣說來,我動態(tài)代理就能作為實現AOP的基了。好了,就說這么多,關于AOP,我可以去關注關于方面的知

          posted on 2009-08-12 16:51 calvin 閱讀(238) 評論(0)  編輯  收藏 所屬分類: Design Patterns

          只有注冊用戶登錄后才能發(fā)表評論。


          網站導航:
           
          主站蜘蛛池模板: 开江县| 江阴市| 芜湖县| 仲巴县| 巴青县| 德阳市| 肃宁县| 潍坊市| 成都市| 马尔康县| 浑源县| 交城县| 锡林郭勒盟| 勐海县| 旅游| 尼勒克县| 冕宁县| 吉安市| 罗源县| 大同县| 湘潭县| 沛县| 镇原县| 仙居县| 台东县| 惠东县| 承德市| 九龙坡区| 常山县| 万州区| 延吉市| 福泉市| 深水埗区| 沐川县| 宜川县| 农安县| 冷水江市| 泸水县| 镇远县| 东兰县| 金沙县|