Proxy.newProxyInstance談proxy模式(轉)


最近一直在看java的設計模式 ,感覺印象最深刻的就是"面向接口編程",在java中,盡量多定義接口,因為設計的最重要的目的就是應對各種變化,而接口本身就是一種變化着的Class的直接反映,通過實現特定接口的各種具體類,達到應對變化的目的,下面以Proxy模式為例:
Proxy的模式最主要的目的,原有的類對象由於某種原因不能訪問,需要通過一個新的類來間接地去實現,這個新的類就稱為代理類,舉個例子說明,老王買/賣魚的例子
public   class  SellFisher  {
    
public int sellFish() {
        System.out.println(
"my fish is delicious!!");
        
return 10;
    }

}
這是一個具體的賣魚類,表示魚10元/斤,如果這個類被用到系統中的時候,系統應對變化的靈活性就會大打折扣,請看如下:
public   class  SellFishSystem  {
    
private SellFisher sellfish;
                     
//...
    public void sellFish() {
        sellfish.sellFish();
    }

}
如果以后魚的價格變化,或者具體的賣魚方法發生變化,就必須修改已經有的SellFisher的sellFish()的代碼,這個情況
使得系統的可擴展性降低,我們肯定會想到解決方案了,定義一個接口,請看代碼:
interface  SellFisher  {
    
int sellFish();
}

public   class  SellFishSystem  {
    
private SellFisher sellfish;
    
public void sellFish() {
        sellfish.sellFish();
    }

}
我們所做的變化,只是把SellFisher從Class提升到Interface,這個時候好處自然很明顯了,這個SellFisher本身就代表
了一種不確定,變化.大家在做開發的時候,閱讀源代碼的時候,肯定遇到過這種情況,總是跟蹤類的對象看代碼實現,如果發現了接口變量,就會比較郁悶,得了解它的具體實現類是什么,這個具體實現類的變化通常就可以應對需求的變化,系以及系統擴展.請看上例子,如果魚的價格變化,或者具體的賣魚方法發生變化,我們只需要新增加SellFisher的實現,
而不必修改已有的代碼,對此我的理解是對系統來說, 新增加一個類的代碼風險要大大低於對已有類的代碼的修改.我覺得這個也是設計模式的立足點吧(如果你喜歡修改已有代碼,那么設計模式就沒有多大意義了)
言歸正傳,有了上面的知識准備,我們接上面的例子來解釋Proxy的模式就簡單多了,比如現在魚的價格變化,賣魚的提示也發生變化了,我們需要一個新的Proxy類來實現
interface  SellFisher {
    
int  sellFish();
}

public   class  ConcreteSellFisher  implements  SellFisher {

    
public   int  sellFish() {
         System.out.println(
" my fish is delicious!! " );
         
return   10 ;
    }

}

public   class  ProxySellFisher  implements  SellFisher {

    
private  SellFisher sell;
    
public  ProxySellFisher(SellFisher sell) {
        
this .sell  =  sell;
    }
    
public   int  sellFish() {
        System.out.println(
" the fish price higher " );
        
return  sell.sellFish() + 10 ;
    }

}
看上面,這個是Proxy模式的代碼例子實現,我們現在在SellFishSystem 使用ProxySellFisher來賣魚了,由ProxySellFisher再調用原來的ConcreteSellFisher類.具體的一些特征總結為:
1.有個代理類Proxy(和原來的實現類繼承同一接口),該類里引用了原來的具體功能實現類(這里是ConcreteSellFisher)
2.重寫實現方法,加一些新的變化的元素(比如魚的價格上漲)
JDK里的Proxy類也實現了這個模式,只不過它叫動態代理,因為它的代理類變成了InvocationHandler了,執行的方法
是invoke了,從而變得更加靈活了,請看代碼
public   class  ProxySellFisher  implements  InvocationHandler {

    
private  SellFisher sell;
    
public  ProxySellFisher(SellFisher sell) {
        
this .sell  =  sell;
    }
    
public  Object invoke(Object obj, Method method, Object[] args)  throws  Throwable {
        System.out.println(
" the fish price higher " );
        
return  (Integer)method.invoke(sell, args) + 10 ;
    }

}


public   class  ClientTest {
    
public   static   void  main(String args[]) {
        SellFisher s 
=   new  ConcreteSellFisher();
        InvocationHandler p 
=   new  ProxySellFisher(s);
        Object obj 
=  Proxy.newProxyInstance(s.getClass().getClassLoader(), s.getClass().getInterfaces(), p);
        ((SellFisher)obj).sellFish();
    }
}
請注意, invoke(Object obj,Method method,Object[] args),這里的第一個參數obj其實可以看作沒有用處的,不知道jdk為什么要把它也當作一個參數放這里,methd.invoke()方法,需要把原來的具體實現類作為參數傳遞進去,method.invoke(obj,args)相當於obj.method(args)
 
總結,從設計模式的角度講,大家以后編程中,盡量要面向接口,更通俗一點就是, 一個類中使用的別的對象成員變量,最好定義成接口的變量而不是實際實現類的變量


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM