天天看點

PHP設計模式之代理模式

代理模式(Proxy),它是對簡單處理程式(或指針)的增強,用于引用一個對象:這個指針被代理(Proxy)對象取代,代理對象位于用戶端(Client)和真實執行程式之間,指針有一個可被多個目标利用的鈎子。

從技術上講,這種模式在用戶端和真實主體(RealSubject)之間插入一個代理對象,維護subject接口和用不同的方式委派它的方法。代理可以透明地做任何事情:懶散建立RealSubject或載入資料,與其它機器交換消息,寫時複制政策等。這與HTTP代理有點類似,其用戶端(如浏覽器)和應用程式依賴于與HTTP伺服器的聯系,代理在管理連接配接時可以完成其它任務,如通路控制和緩存大型下載下傳檔案。

PHP設計模式之代理模式

PHP設計模式中的代理模式示例

代理模式的對象圖與裝飾模式對象圖在結構上類似,但表達的目的各有不同,裝飾者給對象動态增加行為,而代理則控制來自用戶端的通路。此外,代理隻在需要時才建立RealSubject。 

參與者:

◆用戶端(Client):取決于主體(Subject)實作;

◆主體(Subject):RealSubject的抽象;

◆真實主體(RealSubject):完成代價高昂的工作或包含大量的資料;

◆代理(Proxy):為Client提供一個與Subject一緻的引用,僅在需要時才建立RealSubject執行個體或與RealSubject執行個體通信。

下面是兩個被廣泛使用的代理模式例子:

1、對象-關系映射(Orms)在運作中建立代理作為實體類的子類,以實作懶散加載(虛拟代理),這個代理會覆寫所有實體方法,在前面追加一個載入程式,在方法被真正調用前不會包含任何資料,Orms代理支援對象間的雙向關系,不用加載整個資料庫,因為它們被置于目前加載對象圖的邊界。

2、Java RMI使用遠端代理對象(遠端代理),當它們的方法被調用時,代理序列化參數,執行網絡上的請求,委托調用另一個節點上的真實對象,這種技術允許透明地調用遠端對象,不用擔心它們是否在同一台機器上,但這種透明度很容易會使執行速度變慢。

下面的代碼示例實作了一個ImageProxy,推遲了圖像資料的加載。

  1. <?php  
  2. /**  
  3.  * Subject interface.  
  4.  * Client depends only on this abstraction.  
  5.  */ 
  6. interface Image  
  7. {  
  8.     public function getWidth();  
  9.     public function getHeight();  
  10.     public function getPath();  
  11.     /**  
  12.      * @return string   the image's byte stream  
  13.      */ 
  14.     public function dump();  
  15. }  
  16. /**  
  17.  * Abstract class to avoid repetition of boilerplate code in the Proxy  
  18.  * and in the Subject. Only the methods which can be provided without  
  19.  * instancing the RealSubject are present here.  
  20.  */ 
  21. abstract class AbstractImage implements Image  
  22. {  
  23.     protected $_width;  
  24.     protected $_height;  
  25.     protected $_path;  
  26.     protected $_data;  
  27.     public function getWidth()  
  28.     {  
  29.         return $this->_width;  
  30.     }  
  31.     public function getHeight()  
  32.     {  
  33.         return $this->_height;  
  34.     }  
  35.     public function getPath()  
  36.     {  
  37.         return $this->_path;  
  38.     }  
  39. }  
  40. /**  
  41.  * The RealSubject. Always loads the image, even if no dump of the data  
  42.  * is required.  
  43.  */ 
  44. class RawImage extends AbstractImage  
  45. {  
  46.     public function __construct($path)  
  47.     {  
  48.         $this->_path = $path;  
  49.         list ($this->_width, $this->_height) = getimagesize($path);  
  50.         $this->_data = file_get_contents($path);  
  51.     }  
  52.     public function dump()  
  53.     {  
  54.         return $this->_data;  
  55.     }  
  56. }  
  57. /**  
  58.  * Proxy. Defers loading the image data until it becomes really mandatory.  
  59.  * This class does its best to postpone the very expensive operations  
  60.  * such as the actual loading of the BLOB.  
  61.  */ 
  62. class ImageProxy extends AbstractImage  
  63. {  
  64.     public function __construct($path)  
  65.     {  
  66.         $this->_path = $path;  
  67.         list ($this->_width, $this->_height) = getimagesize($path);  
  68.     }  
  69.     /**  
  70.      * Creates a RawImage and exploits its functionalities.  
  71.      */ 
  72.     protected function _lazyLoad()  
  73.     {  
  74.         if ($this->_realImage === null) {  
  75.             $this->_realImage = new RawImage($this->_path);  
  76.         }  
  77.     }  
  78.     public function dump()  
  79.     {  
  80.         $this->_lazyLoad();  
  81.         return $this->_realImage->dump();  
  82.     }  
  83. }  
  84. /**  
  85.  * Client class that does not use the data dump of the image.  
  86.  * Passing blindly a Proxy to this class and to other Clients makes sense  
  87.  * as the data would be loaded anyway when Image::dump() is called.  
  88.  */ 
  89. class Client  
  90. {  
  91.     public function tag(Image $img)  
  92.     {  
  93.         return '<IMG class=fit-image  SRC="'< span>$img->getPath() . '"  alt=""  width="' 
  94.              . $img->getWidth() . '"  height="'   
  95.              . $img->getHeight() . '"   >?< SPAN>;  
  96.     }  
  97. }  
  98. $path = '/home/giorgio/shared/Immagini/kiki.png';  
  99. $client = new Client();  
  100. $image = new RawImage($path); // loading of the BLOB takes place  
  101. echo $client->tag($image), "\n";  
  102. $proxy = new ImageProxy($path);  
  103. echo $client->tag($proxy), "\n"; // loading does not take place even here 

以上代碼實作了PHP的代理模式。簡單來講,代理模式就是為其他對象提供一個代理以控制對這個對象的通路。