隨筆-159  評論-114  文章-7  trackbacks-0
          某些接口的實現(xiàn)類,我們要做一個代理,來代理對這些實現(xiàn)類對象的方法調(diào)用。

          public class SomeClassImpl {
            
          private String userName;  
            
          public SomeClassImpl(final String userName) {
              
          this.userName = userName;
            }
              
              
          public void someMethod( ) {
              System.out.println(
          this.userName);
            }

            
          public void someOtherMethod(final String text) {
              System.out.println(text);
            }

          }


          該類的簡單代理

          public class SomeClassProxy {
            
          private final SomeClassImpl impl;
            
          public SomeClassProxy(final SomeClassImpl impl) {
              
          this.impl = impl;
            }


            
          public void someMethod( ) {
              
          this.impl.someMethod( );
            }

            
          public void someOtherMethod(String text) {
              
          this.impl.someOtherMethod(text);
            }

          }


          使用代理的原因

          有一些原因,你需要做代理來在你的應用和實現(xiàn)類之間插入一些有用的代碼。

          1.實現(xiàn)類的源碼不能拿到。比如第三方實現(xiàn)的。

          2.有時代理要添加的代碼與實現(xiàn)類的功能沒有直接聯(lián)系,不能將那些代碼放入實現(xiàn)者內(nèi)部,會破化一種對象應該只實現(xiàn)一個概念。

          3.實現(xiàn)者所展現(xiàn)出來的特點應該對各種用戶做隱藏。

          4.你可能想隱藏實現(xiàn)方法的名字給用戶,出于一些安全的考慮。這需要代理有一個特殊的面貌,也就是方法名與真正實現(xiàn)者的方法名不同。

          5.也許要的功能依賴于對象所在的上下文。例如,如果計算機連接到工廠的機械手臂,不需要網(wǎng)絡代碼來訪問手臂,但是工廠的另一端確實需要這段代碼。

          6.也許這些功能只是用于在開發(fā)階段。例如,你能使用一個代理來實現(xiàn)程序的跟蹤,來記錄對象的調(diào)用次數(shù)。這代碼在真正部署時不需要。

          7.實現(xiàn)者的位置或許是變化的,就好像企業(yè)編程。對象進行實際的操作在企業(yè)級網(wǎng)絡中,經(jīng)常更換位置取決于負載平衡和故障轉(zhuǎn)移。你可能需要一個智能的代理定位該對象來提供服務給其他用戶。

          工廠的應用

          獲得一個代理,經(jīng)常通過一個工廠對象獲得。使用工廠的原因是因為你不用特別關心哪一種實現(xiàn)者來實現(xiàn)你的功能,只要他們能正確實現(xiàn)就好了。

          public class SomeClassFactory {
            
          public final static SomeClassProxy getProxy( ) {
            SomeClassImpl impl 
          = new SomeClassImpl(System.getProperty("user.name"));
              
          return new SomeClassProxy(impl);
            }

          }


          public class DemoProxyFactory {
            
          public static final void main(final String[] args) {
              SomeClassProxy proxy 
          = SomeClassFactory.getProxy( );
              proxy.someMethod( );
              proxy.someOtherMethod(
          "Our Proxy works!");
            }

          }



          代理與接口

          用戶有時并不想知道實現(xiàn)的具體細節(jié),也就是到底是代理還是真正實現(xiàn)者完成的功能。如果像上面的工廠類的實現(xiàn),用戶必須知道什么情況下,使用何種代理,這對于用戶的使用提高了難度。需要特殊方法來引用合適的代理,Java的接口就使用用于解決這樣的問題。

          為了隔離實現(xiàn)代理的細節(jié),你能使用接口來描述功能。

          public interface SomeClass {
            [
          public abstractvoid someMethod( );
            [
          public abstractvoid someOtherMethod(final String text);
          }


          public class SomeClassImpl implements SomeClass {
            
          // same as before
          }


          public class SomeClassProxy implements SomeClass {
            
          // same as before
          }


          public class SomeClassCountingProxy implements SomeClass {
            
          // same as before
          }


          public class SomeClassFactory {
            
          public static final SomeClass getSomeClassProxy( ) {
                SomeClassImpl impl 
          = new SomeClassImpl(System.getProperty("user.name"));
          if (LOGGER.isDebugEnabled( )) {
                    
          return new SomeClassCountingProxy(impl);      
                }
           else {
                    
          return new SomeClassProxy(impl);      
                }

            }

          }


          使用

          public class DemoInterfaceProxy {
            
          public static final void main(final String[] args) {
              SomeClass proxy 
          = SomeClassFactory.getSomeClassProxy( );
              proxy.someMethod( );
              proxy.someOtherMethod(
          "Our Proxy works!");
            }

          }



          提示

          if (proxy instanceof SomeClassCountingProxy) {

           System.out.println(((SomeClassCountingProxy)proxy).getInvocationCount());

          }

          一個靜態(tài)代理的實例代碼:

          public class SomeClassCountingProxy {
            
          private final SomeClassImpl impl;
            
          private int invocationCount = 0;
            
          public SomeClassCountingProxy(final SomeClassImpl impl) {
              
          this.impl = impl;
            }

            
          public int getInvocationCount( ) {
              
          return invocationCount;
            }

            
          public void someMethod( ) {
              
          this.invocationCount++;
              
          this.impl.someMethod( );
            }

            
          public void someOtherMethod(String text) {
              
          this.invocationCount++;
              
          this.impl.someOtherMethod(text);
            }

          }



          靜態(tài)代理的缺點

          當給不同的對象,編寫相同功能的代理類時,會發(fā)現(xiàn)需要做很多相同的工作,產(chǎn)生很多相同的代碼。例如,都是對實現(xiàn)對象的調(diào)用進行計數(shù),對于不同對象,要有不同的代理,但是實際上,他們的邏輯是一樣的。這么多代碼不容易維護,一個改了,所有的都要修改,是很可怕的。

          動態(tài)代理,主要使用反射來實行。

          主要工作是實現(xiàn)一個InvocationHandler,他會截住對實現(xiàn)者的調(diào)用,進行一些邏輯,這時在將請求發(fā)給實現(xiàn)者,一旦實現(xiàn)者返回,invocationhandler也返回結果。

          public class MethodCountingHandler implements InvocationHandler {
            
          private final Object impl;
            
          private int invocationCount = 0;
            
          public MethodCountingHandler(final Object impl) {
              
          this.impl = impl;
            }

            
          public int getInvocationCount( ) {
              
          return invocationCount;
            }

            
          public Object invoke(Object proxy, Method meth, Object[] args)
                          
          throws Throwable {
              
          try {
                
          this.invocationCount++;
                Object result 
          = meth.invoke(impl, args);
                
          return result;
              }
           catch (final InvocationTargetException ex) {
                
          throw ex.getTargetException( );
              }

            }

          }


          這代理提供著與靜態(tài)代理相同的功能。然而,他使用反射來完成工作的,當用戶執(zhí)行代理的方法時,invocation handler被替換成實現(xiàn)者來被調(diào)用。在其內(nèi)部增加了invocationCount的值并轉(zhuǎn)發(fā)調(diào)用給實現(xiàn)者通過調(diào)用Method對象的invoke()方法。一旦調(diào)用完成,實現(xiàn)將會返回一個valuehandler。可以將value返回給調(diào)用者。

          When writing invocation handlers, be careful of methods that return primitive types. The JDK will wrap primitive types in their corresponding wrapper types to return them from a reflexive invocation. The problem is that your handler can return null, but the actual method being called on the implementation cannot. Therefore, if you try to return null after calling a method that returns a primitive, the proxy class will throw a NullPointerException. This NullPointerException applies to the return value, not to the parameters of the method.

          可以在invoke方法中加入復雜的邏輯。

          得到一個實現(xiàn)者接口的實現(xiàn)者(這里當然就是那個動態(tài)代理對象),通過工廠。

          public class SomeClassFactory {
            
          public static final SomeClass getDynamicSomeClassProxy( ) {
              SomeClassImpl impl 
          = new SomeClassImpl(System.getProperty("user.name"));
              InvocationHandler handler 
          = new MethodCountingHandler(impl);
              Class[] interfaces 
          = new Class[] { SomeClass.class };
              ClassLoader loader 
          = SomeClassFactory.class.getClassLoader( );
              SomeClass proxy 
          = (SomeClass)Proxy.newProxyInstance(loader, 
                                                                  interfaces, 
                                                                  handler);
              
          return proxy;
            }

          }



          In this version of the factory method, SomeClass is an interface implemented by the actual implementation, named SomeClassImpl. This allows you to tell the Proxy class to generate a new proxy that implements the interface SomeClass and uses the invocation handler.

           

          One limitation of this system is that the implementation class must implement the interfaces used in the proxy. Therefore, if the implementation did not implement the interface in the first place and the source code is out of your control, this paradigm won't work.

          public class DemoDynamicProxy {
            
          public static final void main(final String[] args) {
              SomeClass proxy 
          = SomeClassFactory.getDynamicSomeClassProxy( );
              proxy.someMethod( );
              proxy.someOtherMethod(
          "Our Proxy works!");
            }
            
          }


          InvocationHandler handler = Proxy.getInvocationHandler(proxy);

          if (handler instanceof MethodCountingHandler) {

            System.out.println(((MethodCountingHandler)handler).getInvocationCount( ));

          }

          ===========================================================================================

           

          package com.ljl.proxy;

          import java.lang.reflect.InvocationHandler;
          import java.lang.reflect.Method;
          import java.lang.reflect.Proxy;
          import java.util.List;
          import java.util.Vector;

          public class VectorProxy implements InvocationHandler{

              
          private Object proxyobj;
              
          public VectorProxy(Object obj) {
                  
          super();
                  
          this.proxyobj = obj;
              }


              
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  
                  System.out.println(
          "before calling " + method);
                  
          if(args!=null)
                  
          {
                      
          for(int i = 0; i < args.length;i++)
                      
          {
                          System.out.println(args[i]
          +" ");
                      }

                  }

                  Object o 
          = method.invoke(proxyobj,args);        
                  System.out.println(
          "after calling " + method);
                  
                  
          return o;
              }

              
              
          public static Object factory(Object obj)
              
          {
                  Class cls 
          = obj.getClass();
                  
          return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),new VectorProxy(obj));
              }

              
              
          public static void main(String[] args)
              
          {
                  List v 
          = null;
                  v 
          = (List)factory(new Vector(10));
                  v.add(
          "ljl");
                  v.add(
          "hus");
              }


          }



          posted on 2006-01-30 18:27 北國狼人的BloG 閱讀(2024) 評論(0)  編輯  收藏

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


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 玉山县| 于田县| 西城区| 叙永县| 红安县| 孝义市| 台中市| 崇文区| 中方县| 伊通| 临桂县| 长寿区| 宜州市| 新田县| 台江县| 浮山县| 潮州市| 班玛县| 桐乡市| 廊坊市| 临澧县| 甘孜| 溧水县| 阳谷县| 砚山县| 兰州市| 徐汇区| 剑川县| 达孜县| 云安县| 大方县| 琼海市| 罗源县| 万盛区| 康乐县| 康定县| 云浮市| 江西省| 巍山| 巨鹿县| 德令哈市|