javascript设计模式-三种代理

桥接

将抽象与实现隔离开来,以便二者独立变化。常用于事件驱动的程序设计。有些地方它和适配器与门面很类似。下面是最简单的桥接模式,但适配器是一种包装器。门面一般是同一个类中方法的抽象和组合,而桥接通常是收集几个类的。

这种方式也要注意使用场合,如果一个函数只在一个地方专用,那就没必要用Bridge把它桥接出来。有些设计模式和队列混合使用会起到意想不到的效果。

javascript 复制代码
addEvent(element, 'click', getBeerByIdBridge);
function getBeerByIdBridge (e) {
  //这里把参数分开后,可以随便调用多个具体实现类,而JS又与参数无关
  getBeerById(this.id, function(beer) {
    console.log('Requested Beer: '+beer);
  });
}

目的:通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变

原则 ✴将实现解耦,让它和界面之间不再永久绑定 ✴抽象和实现可以独立扩展,不会影响到对方 ✴适用于使用在需要跨多个平台上的图形和窗口系统上 ✴缺点是增加了系统的复杂度。

适配器

可用来在现有接口和不兼容的类之间进行适配,又称为「包装器」。适配器可以被添加到现有代码中以协调两个不同的接口。适配器有利于大批量改写现有代码,但有时改写现有代码可能会比较方便。这种优化有点类似于JDK升级过程中保留老的API,但建议使用新的API的过程。

门面元素展现的是一个简化接口,它并不提供额外的选择,而且有时为了方便完成某些常见任务它还会做出一些选择和假定。而适配器则要把一个接口转换为另一个接口,它并不会滤除某些能力,也不会简化接口。最简单的例子如下:

javascript 复制代码
var clientObject = {
  string1: 'foo',
  string2: 'bar',
  string3: 'baz'
};
function interfaceMethod(str1, str2, str3) {
  //doSomeThing
}
//适配器,为了适配interfaceMethod接口
function clientToInterfaceAdapter(o) {
  interfaceMethod(o.string1, o.string2, o.string3);
}
/* Usage. */
clientToInterfaceAdapter(clientObject);

// Prototype $ function.
function $() {
  var elements = new Array();
  return elements;
}
/* YUI get method. */
YAHOO.util.Dom.get = function(el) {
  return el;
};

function PrototypeToYUIAdapter() {
  return YAHOO.util.Dom.get(arguments);
}
function YUIToPrototypeAdapter(el) {
  return $.apply(window, el);
}
//使用时,从Prototype切换到YUI,需要添加如下代码,这样就不需要修改原有代码了,只需要把原来提供的API重新封装一次即可
$ = PrototypeToYUIAdapter;
//使用时,从YUI切换到Prototype,需要添加如下代码
YAHOO.util.Dom.get = YUIToPrototypeAdapter;

代理是一个对象,它可以用来控制对另一对象的访问。它与另一个对象实现同样的接口,并且会把任何方法调用传递给那个对象。另外那个对象通常称为本体。代理可以代替其本体被实例化,并使其可被远程访问。它还可以把本体的实例化推迟到真正需要的时候。

对于实例化比较费时的本体,或尺寸比较大以至于不用时不宜保存在内存中的本体这特别有用。另外在处理那些需要较长时间才能把数据载入用户界面的类时,代理也非常有用。代理最适合的场景就是创建一个开销昂贵的资源访问。

代理

简单的代理(不常用)

这个例子没有什么实际的作用,可以做为优化的预留接口。

虚拟代理(常用)

在用到时再实例化本体,其网页加载时可能没办法一步初始化PublicLibrary。在第一次调用时才会实例化,这可能会导致第一次调用时时间会比较慢。

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

通用代理模式

一般用来处理加载数据量或处理比较慢的程序,可以在加载前显示正在处理等字样。它们的缺点就是掩盖了本体的大量细节,而且可以直接和本体互换。所以最好是高质量的文档化。

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 = {}; //触发本体的实例化过程.
    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.');
  }
};

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.
};
相关推荐
学不会•22 分钟前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNTS1 小时前
H.264/H.265播放器EasyPlayer.js视频流媒体播放器关于websocket1006的异常断连
javascript·h.265·h.264
Theodore_10221 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
活宝小娜3 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点3 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow3 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o3 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
----云烟----3 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024063 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端