js 设计模式 第十四章 Proxy Pattern

来源:互联网 发布:老男孩linux运维 编辑:程序博客网 时间:2024/05/22 09:43

why?

1 如果某对象的创建比较耗资源,吃内存。一个方案,就是当用户真正调用对象的方法时,才让真实对象实例化。暴露给用户的是,那个真实对象的代理,它的创建不会消耗太多的资源,这里说的就是virtural proxy。

2 让网络上的数据,用起来像是本地数据。屏蔽网络请求、错误处理等复杂的底层处理。remote proxy 就是一个远程资源的代理。

how?

proxy 的核心是:proxy 实现真实对象的方法,他不会对真实对象的方法进行添、删、改。

what?

proxy 是对某个对象进行访问控制的对象,proxy 对象实现了同真实访问对象一样的接口,通过传递,最终还是真实的访问对象去实施相应的方法。proxy 对象不会添加和修改接口的方法(decorator 会修改或添加),也不会像facade那样简化接口。proxy 实现真实对象一样的接口,并直接传递给真实对象的方法

入门proxy

最简单的proxy 是不进行访问控制,它简单地把任何方法的调用,直接转换为真实对象的方法调用。这样的proxy 没有什么用途,但是却提供了一个基本的proxy 框架

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']);var PublicLibrary = function(books) { // implements Librarythis.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){},checkoutBook : function(book){},returnBook : function(book){}};/* 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);}};

可以看到,PublicLibraryProxy 实现了同PublicLibrary 一样的接口。当proxy 实例化后,他同时也实例化了一个PublicLibrary 对象,将他作为一个属性。任何时候,当PublicLibraryProxy的方法调用的时候,他将最终调用的是PublicLibrary 对象的那个方法。

virtual proxy

这个例子用途不大,但是他的变种virtual Proxy 却是proxy 最常用的一种方式。virtual Proxy 适用场景是针对复杂、创建耗资源的对象。virtual proxy 将延迟真实对象的访问,直到对象的方法被访问。比如说:PublicLibrary 实例化很慢,这时用virtual proxy 来延迟加载

/* 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);}};

PublicLibraryVirtualProxy 没有立即实例PublicLibrary 对象,他在构造函数中存储了参数,知道方法被调用时,才真正实例化对象。这样,如果方法一直没有被调用,这个兑奖就永远不会被创建。

remote proxy

remote proxy 用来封装远程数据,让用户使用远程数据的时候,像是使用本地数据一样。

一个remote proxy 的一般实现

/* WebserviceProxy class */var WebserviceProxy = function() {    this.xhrHandler = XhrManager.createXhrHandler();};WebserviceProxy.prototype = {_xhrFailure: function(statusCode) {    throw new Error('StatsProxy: Asynchronous request for stats failed.');},_fetchData: function(url, dataCallback, getVars) {    var that = this;    var callback = {success: function(responseText) {    var obj = eval('(' + responseText + ')');    dataCallback(obj);        },        failure: that._xhrFailure    };    var getVarArray = [];    for(varName in getVars) {        getVarArray.push(varName + '=' + getVars[varName]);    }    if(getVarArray.length > 0) {        url = url + '?' + getVarArray.join('&');    }    xhrHandler.request('GET', url, callback);}};

这个proxy 作为基类,子类实现利用基类的_fetchData方法实现对远程数据的访问、处理

例如:

/* StatsProxy class. */var StatsProxy = function() {}; // implements PageStatsextend(StatsProxy, WebserviceProxy);/* Implement the needed methods. */StatsProxy.prototype.getPageviews = function(callback, startDate, endDate,page) {    this._fetchData('/stats/getPageviews/', callback, {'startDate': startDate,'endDate': endDate,'page': page});};StatsProxy.prototype.getUniques = function(callback, startDate, endDate,page) {    this._fetchData('/stats/getUniques/', callback, {'startDate': startDate,'endDate': endDate,'page': page});};StatsProxy.prototype.getBrowserShare = function(callback, startDate, endDate,page) {    this._fetchData('/stats/getBrowserShare/', callback, {'startDate': startDate,'endDate': endDate,'page': page});};

为 remote proxy 创建了一个通用的基类,我们也为remote proxy 创建一个基类吧

/* 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.');    }};

基类有三个方法,_initialize 用来实例化真实对象的方法;_checkInitialization用来。。。

/* 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);    }};





原创粉丝点击