Proxy Pattern in Javascript

  1. 代理與本體 (RealObject) 實現同樣的接口
  2. 代理工作時,實際也是通過本體工作,call 本體的方法
  3. 代理並不會在本體的基礎上進行修改, 否則就是裝飾模式

Example 1

/* From chapter 3. */

var Publication = new Interface('Publication', ['getIsbn', 'setIsbn', 'getTitle',
  'setTitle', 'getAuthor', 'setAuthor', 'display']);
var Book = function(isbn, title, author) { ... } // implements Publication

/* Library interface. */

var Library = new Interface('Library', ['findBooks', 'checkoutBook', 'returnBook']);

/* PublicLibrary class. */

var PublicLibrary = function(books) { // implements Library
  this.catalog = {};
  for(var i = 0, len = books.length; i < len; i++) {
    this.catalog[books[i].getIsbn()] = { book: books[i], available: true };
  }
};
PublicLibrary.prototype = {
  findBooks: function(searchString) {
    var results = [];
    for(var isbn in this.catalog) {
      if(!this.catalog.hasOwnProperty(isbn)) continue;
      if(searchString.match(this.catalog[isbn].getTitle()) ||
          searchString.match(this.catalog[isbn].getAuthor())) {
        results.push(this.catalog[isbn]);
      }
    }
    return results;
  },
  checkoutBook: function(book) {
    var isbn = book.getIsbn();
    if(this.catalog[isbn]) {
      if(this.catalog[isbn].available) {
        this.catalog[isbn].available = false;
        return this.catalog[isbn];
      }
      else {
        throw new Error('PublicLibrary: book ' + book.getTitle() +
          ' is not currently available.');
      }
    }
    else {
      throw new Error('PublicLibrary: book ' + book.getTitle() + ' not found.');
    }
  },
  returnBook: function(book) {
    var isbn = book.getIsbn();
    if(this.catalog[isbn]) {
      this.catalog[isbn].available = true;
    }
    else {
      throw new Error('PublicLibrary: book ' + book.getTitle() + ' not found.');
    }
  }
};

Example 2

/* PublicLibraryProxy class, a useless proxy. */

var PublicLibraryProxy = function(catalog) { // implements Library
  this.library = new PublicLibrary(catalog);
};
PublicLibraryProxy.prototype = {
  findBooks: function(searchString) {
    return this.library.findBooks(searchString);
  },
  checkoutBook: function(book) {
    return this.library.checkoutBook(book);
  },
  returnBook: function(book) {
    return this.library.returnBook(book);
  }
};

/* PublicLibraryVirtualProxy class. */

var PublicLibraryVirtualProxy = function(catalog) { // implements Library
  this.library = null;
  this.catalog = catalog; // Store the argument to the constructor.
};
PublicLibraryVirtualProxy.prototype = {
  _initializeLibrary: function() {
    if(this.library === null) {
      this.library = new PublicLibrary(this.catalog);
    }
  },
  findBooks: function(searchString) {
    this._initializeLibrary();
    return this.library.findBooks(searchString);
  },
  checkoutBook: function(book) {
    this._initializeLibrary();
    return this.library.checkoutBook(book);
  },
  returnBook: function(book) {
    this._initializeLibrary();
    return this.library.returnBook(book);
  }
};

有些類或對象的創建開銷大,而且不需要在實例化后立即訪問其數據 http://blog.thankphp.net/?p=22

Example 3: DirectoryProxy

/* Directory interface. */

var Directory = new Interface('Directory', ['showPage']);

/* PersonnelDirectory class, the Real Subject */

var PersonnelDirectory = function(parent) { // implements Directory
  this.xhrHandler = XhrManager.createXhrHandler();
  this.parent = parent;
  this.data = null;
  this.currentPage = null;

  var that = this;
  var callback = {
    success: that._configure,
    failure: function() {
      throw new Error('PersonnelDirectory: failure in data retrieval.');
    }
  }
  xhrHandler.request('GET', 'directoryData.php', callback);
};
PersonnelDirectory.prototype = {
  _configure: function(responseText) {
    this.data = eval('(' + reponseText + ')');
    ...
    this.currentPage = 'a';
  },
  showPage: function(page) {
    $('page-' + this.currentPage).style.display = 'none';
    $('page-' + page).style.display = 'block';
    this.currentPage = page;
  }
};

/* DirectoryProxy class, just the outline. */

var DirectoryProxy = function(parent) { // implements Directory

};
DirectoryProxy.prototype = {
  showPage: function(page) {

  }
};

/* DirectoryProxy class, as a useless proxy. */

var DirectoryProxy = function(parent) { // implements Directory
  this.directory = new PersonnelDirectory(parent);
};
DirectoryProxy.prototype = {
  showPage: function(page) {
    return this.directory.showPage(page);
  }
};

/* DirectoryProxy class, as a virtual proxy. */

var DirectoryProxy = function(parent) { // implements Directory
  this.parent = parent;
  this.directory = null;
  var that = this;
  addEvent(parent, 'mouseover', that._initialize); // Initialization trigger.
};
DirectoryProxy.prototype = {
  _initialize: function() {
    this.directory = new PersonnelDirectory(this.parent);
  },
  showPage: function(page) {
    return this.directory.showPage(page);
  }
};

/* DirectoryProxy class, with loading message. */

var DirectoryProxy = function(parent) { // implements Directory
  this.parent = parent;
  this.directory = null;
  this.warning = null;
  this.interval = null;
  this.initialized = false;
  var that = this;
  addEvent(parent, 'mouseover', that._initialize); // Initialization trigger.
};
DirectoryProxy.prototype = {
  _initialize: function() {
    this.warning = document.createElement('div');
    this.parent.appendChild(this.warning);
    this.warning.innerHTML = 'The company directory is loading...';

    this.directory = new PersonnelDirectory(this.parent);
    var that = this;
    this.interval = setInterval(that._checkInitialization, 100);
  },
  _checkInitialization: function() {
    if(this.directory.currentPage != null) {
      clearInterval(this.interval);
      this.initialized = true;
      this.parent.removeChild(this.warning);
    }
  },
  showPage: function(page) {
    if(!this.initialized) {
      return;
    }
    return this.directory.showPage(page);
  }
};

Example 4: DynamicProxy

遠程代理: 有某種遠程資源, 並且為該資源提供的所有功能實現對應的方法.

webproxy

/* DynamicProxy abstract class, incomplete. */

var DynamicProxy = function() {
  this.args = arguments;
  this.initialized = false;
};
DynamicProxy.prototype = {
  _initialize: function() {
    this.subject = {}; // Instantiate the class.
    this.class.apply(this.subject, this.args);
    this.subject.__proto__ = this.class.prototype;

    var that = this;
    this.interval = setInterval(function() { that._checkInitialization(); }, 100);
  },
  _checkInitialization: function() {
    if(this._isInitialized()) {
      clearInterval(this.interval);
      this.initialized = true;
    }
  },
  _isInitialized: function() { // Must be implemented in the subclass.
    throw new Error('Unsupported operation on an abstract class.');
  }
};

/* DynamicProxy abstract class, complete. */

var DynamicProxy = function() {
  this.args = arguments;
  this.initialized = false;

  if(typeof this.class != 'function') {
    throw new Error('DynamicProxy: the class attribute must be set before ' +
      'calling the super-class constructor.');
  }

  // Create the methods needed to implement the same interface.
  for(var key in this.class.prototype) {
    // Ensure that the property is a function.
    if(typeof this.class.prototype[key] !== 'function') {
      continue;
    }

    // Add the method.
    var that = this;
    (function(methodName) {
      that[methodName] = function() {
        if(!that.initialized) {
          return
        }
        return that.subject[methodName].apply(that.subject, arguments);
      };
    })(key);
  }
};
DynamicProxy.prototype = {
  _initialize: function() {
    this.subject = {}; // Instantiate the class.
    this.class.apply(this.subject, this.args);
    this.subject.__proto__ = this.class.prototype;

    var that = this;
    this.interval = setInterval(function() { that._checkInitialization(); }, 100);
  },
  _checkInitialization: function() {
    if(this._isInitialized()) {
      clearInterval(this.interval);
      this.initialized = true;
    }
  },
  _isInitialized: function() { // Must be implemented in the subclass.
    throw new Error('Unsupported operation on an abstract class.');
  }
};

/* TestProxy class. */

var TestProxy = function() {
  this.class = TestClass;
  var that = this;
  addEvent($('test-link'), 'click', function() { that._initialize(); });
    // Initialization trigger.
  TestProxy.superclass.constructor.apply(this, arguments);
};
extend(TestProxy, DynamicProxy);
TestProxy.prototype._isInitialized = function() {
  ... // Initialization condition goes here.
};

 

附錄

Observer pattern in java

http://www.darkmi.com/blog/archives/1961

article clipper remember Proxy Pattern in Javascript
 
  1. 目前没有评论。

  1. 目前没有引用通告。