一日一摸之第六日 proxy代理模式

     如果創建一個對象需要花費較多的時間,做較多的工作,同時還不確定後面會不會實際用上,如你在超市買手機,就給一個模型給你看就得了,你確定要的時候纔去拿一個真機器來給你,這裏這個手機模型可以看作是手機的一個代理。還有現在的藝人都會有經紀人,大部分事情你跟他的經紀人聯繫就搞定了,在登臺演出的時候,經紀人自然會安排藝人Live Show。這裏經紀人就是藝人的一個Proxy。同時在Proxy這裏還可以做一個權限控制,做一層過濾,如在經紀人這裏,看你拿不出100W,根本就不會安排藝人演出,藝人也根本就不知道你這個事情,在打印機那裏,在打印的時候,也可以做一個權限控制,只有在你具有打印機的操作權限時纔會讓你打印。權限驗證沒有通過,打印機對象根本就不會生成。JLive的Forum就使用Proxy進行了權限控制。

 
打印機程序實例,在真正需要打印的時候才生成打印機對象:
/**
 *@(#)Printable.java1.02007-10-23
 */
package pattern.proxy;
 
/**
 *@authortsimgsong
 *
 */
publicinterface Printable {
    
     /**
      *Nameprinter
      *@paramname
      */
     publicvoid setPrinterName(String name);
    
     /**
      *getPrinterName
      *@return
      */
     public String getPrinterName();
    
     /**
      *printcontent
      *@paramcnt
      */
     publicvoid print(String cnt);
 
}
 
 
/**
 * @(#)Printer.java 1.0 2007-10-23
 */
package pattern.proxy;
 
import org.apache.log4j.Logger;
 
/**
 * @author tsimgsong
 *
 */
public class Printer implements Printable {
      
       private String name;
      
       static Logger logger = Logger.getLogger(Printer.class);
      
       public Printer(){
              logger.info("Initializing Printer begin ...");
              logger.info("Initialize Printer end ");
       }
      
       public Printer(String name){
              this.name = name;
       }
 
       public String getPrinterName() {
              return name;
       }
 
       public void print(String cnt) {
              logger.info("Print Begin");
              logger.info("Print End");
       }
 
       public void setPrinterName(String name) {
              this.name = name;
       }
 
}
 
/**
 * @(#)PrinterProxy.java 1.0 2007-10-23
*/
package pattern.proxy;
 
/**
 * @author tsimgsong
 *
 */
public class PrinterProxy implements Printable {
       private String name ;
      
       private Printer printer;
 
       public PrinterProxy(){
             
       }
      
       public PrinterProxy(String name){
              this.name = name;
       }
      
       public String getPrinterName() {
              return name;
       }
 
       public void print(String cnt) {
              realPrinter();
              printer.print(cnt);          
       }
 
       public synchronized void setPrinterName(String name) {
              if(printer != null){
                     printer.setPrinterName(name);
              }
              this.name = name;
       }
      
       private synchronized void realPrinter(){
              if(printer == null){
                     printer = new Printer(name);
              }           
       }
}
如對打印機的使用進行權限控制,就不要客戶端直接生成Printer對象,要打印都通過PrinterProxy來打印,在打印的地方對客戶端權限進行判定。
public void print(PrintPermission permission,String cnt) throws PrintException,UnauthorizedException {
    if(permission.canPrint()){
              realPrinter();
              printer.print(cnt);          
}else{
        Throw new UnauthorizedException();
}
}
 
使用Java提供的動態代理:(JAVA提供了一個Proxy類和一個InvocationHandler,這兩個類都在java.lang.reflect包中。程序員通過實現java.lang.reflect.InvocationHandler接口提供一個執行處理器,然後通過java.lang.reflect.Proxy得到一個代理對象,通過這個代理對象來執行方法,方法被調用的同時,執行處理器會被自動調用。)
package pattern.proxy;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
/**
 *@authortsimgsong
 *
 */
publicclass DynamicProxy implements InvocationHandler{
    
     private Object original;
    
     public DynamicProxy(Object orig){
         this.original = orig;
     }
 
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//這裏可以加上權限控制
         Object obj = method.invoke(original, args);
         return obj;
     }
    
     publicstaticvoid main(String args[]){
         Printer pp = new Printer();
         DynamicProxy dp = new DynamicProxy(pp);
         Printable p = (Printable)Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new Class[]{Printable.class}, dp);
         p.print("ddddd"); }
}
程序首先創建一個被代理對象然後初始化代理對象,最後由Proxy的newProxyInstance獲得一個代理實例, newProxyInstance方法有三個參數, ClassLoader, Class[] interfaces, InvocationHandler。ClassLoader是當前的類加載器,interfaces是代理實例要實現的接口的類(需要指出java的Proxy是針對接口的,如果傳入的Class類型不是接口,會拋出IllegalArgumentException異常)。InvocationHandler則是我們寫的代理處理器。newProxyInstance獲得的實例對象的類是通過修改java二進制文件來獲得的,Proxy中有一個private static native Class defineClass0(ClassLoader loader, String name,byte[] b, int off, int len);方法,這個本地方法實現了這個Class的生成,至於具體的實現我們無法看到,不過很多資料上都有關於native方法的討論。
 
Ref:
2、 http://boool.blogdriver.com/boool/284115.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章