java代理模式之靜態代理


  作為一個初級開發者,可能不會接觸到代理模式,但是在很多框架的使用中都不知不覺使用了代理模式,比如servlet的過濾器鏈,spring的AOP,以及spring mvc的攔截器等。所以了解代理模式對於個人的成長是不可避免的。

  在某些情況下,一個客戶不想或者不能直接引用一個對象,此時可以通過一個稱之為“代理”的第三者來實現間接引用。代理對象可以在客戶端和目標對象之間起到中介的作用,並且可以通過代理對象去掉客戶不能看到的內容和服務或者添加客戶需要的額外服務。

原文和作者一起討論:http://www.cnblogs.com/intsmaze/p/6013461.html

    通過引入一個新的對象來實現對真實對象的操作或者將新的對象作為真實對象的一個替身,這種實現機制即為代理模式,通過引入代理對象來間接訪問一個對象,這就是代理模式的模式動機。 
 
     代理模式(Proxy Pattern) :給某一個對象提供一個代理,並由代理對象控制對原對象的引用。代理模式的英文叫做Proxy或Surrogate,它是一種對象結構型模式。

    代理模式示意結構圖比較簡單,一般可以簡化為如下圖所示,但是在現實中要復雜很多。

 
如下的場景來理解為什么采用聚合而不是繼承調用:
public interface Moveable {
    void move();
    void stop();
}
public class Tank implements Moveable {
    public void move() {        
        System.out.println("Tank Move");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }        
    }    
    public void stop() {       
        System.out.println("Tank stop");
    }    
}  
現在我們要增加一個功能,記錄move方法的執行時間,不能修改源碼。

方式1:采用繼承

public class Tank1 extends Tank {
    public void move() {        
        System.out.println("time start");
        super.move();
        System.out.println("time end");
    }    
}  

再增加一個功能,記錄move的執行前后的日志信息,不能修改源碼。

public class Tank2 extends Tank {
    public void move() {        
        System.out.println("log start");
        super.move();
        System.out.println("log end");
    }    
}  
但是要是想先記錄日志在記錄時間,那么就要再創建一個類繼承Tank1類。
要先記錄時間再記錄日志,就要再創建一個類繼承Tank2類。
代理模式不采用繼承模式,因為擴展性很差的。
 

方式二:采用聚合模式

public class TimeProxy implements Moveable {
    Moveable m;   
    public TimeProxy(Moveable m) {
        super();
        this.m = m;
    }
    public void move() {        
        System.out.println("time start");
        m.move();
        System.out.println("time end");
    }    
} 

public class LogProxy implements Moveable {
    Moveable m;   
    public LogProxy(Moveable m) {
        super();
        this.m = m;
    }
    public void move() {        
        System.out.println("log start");
        m.move();
        System.out.println("log end");
    }    
}

想添加日志功能

  public static void main(String[] args) throws Exception {
        Moveable t = new Tank();
        Moveable m=new LogProxy(t);
        m.move();
    }

想先日志再時間,直接在調用處進行組合,不需要創建新的類

public static void main(String[] args) throws Exception {
        Moveable t = new Tank();
        Moveable m=new LogProxy(t);
        Moveable s=new TimeProxy(m);
        s.move();
    }

如果要對Moveable接口中所有的方法加時間計算

public class TimeProxy implements Moveable {
    Moveable m;   
    public TimeProxy(Moveable m) {
        super();
        this.m = m;
    }
    public void move() {     
        this.before();
        m.move();
        this.after();     
   }
    @Override
    public void stop() {     
        this.before();
        m.stop();
        this.after();       
    }    
    public void before()
    {
        System.out.println("time start");
    }
    public void after()
    {
        System.out.println("time end");
    }
}

代理模式的優點

代理模式能夠協調調用者和被調用者,在一定程度上降低了系統的耦合度。
遠程代理使得客戶端可以訪問在遠程機器上的對象,遠程機器可能具有更好的計算性能與處理速度,可以快速響應並處理客戶端請求。
虛擬代理通過使用一個小對象來代表一個大對象,可以減少系統資源的消耗,對系統進行優化並提高運行速度。
保護代理可以控制對真實對象的使用權限。

代理模式的缺點

由於在客戶端和真實主題之間增加了代理對象,因此有些類型的代理模式可能會造成請求的處理速度變慢。
實現代理模式需要額外的工作,有些代理模式的實現非常復雜。

 

 


免責聲明!

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



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