Proxy Pattern

The pattern allows:

  • access control for the subject object;
  • added functionality when an object is accessed.

Proxy Pattern


You may know the pattern from its implementations on network-connection. In programming that is also an intervening layer. Proxy is an object of the same interface with the subject and is meant to control access to the subject object.


PHP Example

The proxy pattern is widely used, though, apparently, the simplest example would be cache proxy. The example actually uses Proxy to implement the Flyweight pattern.


<?php
/*
 * @category Design Pattern Tutorial
 * @package Proxy Sample
 * @author Dmitry Sheiko <me@dsheiko.com>
 * @link http://dsheiko.com
 */
/**
 * Subject interface
 */
interface Entry_Interface
{
    public function get();
}
/**
 * Subject
 */
class Entry implements Entry_Interface
{
    private $_id;
    public function  __construct($id)
    {
        $this->_id;
    }
    public function get()
    {
        return "Entry #{$this->_id} retrieved";
    }
}
/**
 * Proxy
 */
class Entry_ChacheProxy implements Entry_Interface
{
    private $_id;
    public function  __construct($id)
    {
        $this->_id;
    }
    public function get()
    {
        static $entry = null;
        if ($entry === null) {
            $entry = new Entry($this->_id);
        }
        return $entry->get();
    }
}

/**
 * Usage
 */
$entryId = 1;
$entry = new Entry_ChacheProxy($entryId);
echo $entry->get(), "\n"; // loading necessary
echo $entry->get(), "\n"; // loading unnecessary

JS/ES5 Example

Another cache proxy, but this time dealing with asynchronous requests.

/*
 * @category Design Pattern Tutorial
 * @package Proxy Sample
 * @author Dmitry Sheiko <me@dsheiko.com>
 * @link http://dsheiko.com
 */
(function() {
/**
 * Abstract object for data source
 */
var DataSource = function(url) {
   this.url = url;
   return {
       makeRequest: function(method, paramString) {
            var _xhr = new XMLHttpRequest(),
            _scope = this;
            _xhr.open(method, this.url, true);
            _xhr.onreadystatechange = function() {
                if (_xhr.readyState === 4 && _xhr.status == 200 &&_xhr.responseText.length) {
                   _scope.onMessageProxy(JSON.parse(_xhr.responseText));
                }
            };
            _xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
            _xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            _xhr.send(paramString);
       },
       get : function(params) {
           this.makeRequest("POST", params);
       },
       onMessageProxy: function(data) {
           this.onMessage(data);
       }
   }
};
/**
 * Concrete data source
 */
// Let's extends PageDataSource with DataSource
var PageDataSource = function(url) {
    this.url = url;
}
PageDataSource.prototype = new DataSource();
PageDataSource.prototype.get = function(pageId) {
    this.makeRequest("POST", 'pageId=' + pageId);
};

/**
 * Proxy object for the data source
 */
// Let's extends PageDataSourceCacheProxy with PageDataSource
var PageDataSourceCacheProxy = function(url)
{
    this.url = url;
    this._storage = [];
}
PageDataSourceCacheProxy.prototype = new PageDataSource();
PageDataSourceCacheProxy.prototype.get = function(pageId) {
    return (this._storage[pageId]
        ? this.onMessageProxy(this._storage[pageId])
        : this.makeRequest("POST", 'pageId=' + pageId));
};
PageDataSourceCacheProxy.prototype.onMessageProxy = function(data) {
    this._storage[data.pageId] = data;
    this.onMessage(data);
};

/**
 * Usage
 */
var pageId = 2,
    src = new PageDataSourceCacheProxy('testController.php');

src.onMessage = function(data) {
   // When first time requested, it is delivered by XMLHttpRequest
   // when the secind time, just taken from cache
   console.log(data);
}
src.get(pageId);
// Let's wait before first request cached and then request
setTimeout(function() {
    src.get(pageId)
}, 1000);

})();