Proxy Pattern in Javascript
- 代理與本體 (RealObject) 實現同樣的接口
- 代理工作時,實際也是通過本體工作,call 本體的方法
- 代理並不會在本體的基礎上進行修改, 否則就是裝飾模式
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
目前没有评论。