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.
};
相关推荐
_阿南_1 小时前
项目中新增给AI制定的代码规范
前端·程序员
名字还没想好☜2 小时前
React 实现暗黑模式切换:localStorage 持久化、SSR 首屏闪烁与跟随系统主题
前端·javascript·react.js·ecmascript·react·next.js
kruptos3 小时前
分布式系统怎么“选主“?Raft 共识一次讲清
开发语言·分布式·php·共识算法
吴声子夜歌3 小时前
ApacheCommons——commons-cli(命令行参数解析)
java·开发语言·apache
自动化监测Learner3 小时前
主流 Web 端地图引擎对比:选型指南与优劣分析
javascript
console.log('npc')3 小时前
Git 冲突与 AI 协助指南
前端·人工智能·git·大模型
benchmark_cc4 小时前
REST API 和 Python SDK 应该怎么选?量化交易数据接口选型实战
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
王的宝库4 小时前
Go 项目结构:从单文件到标准工程布局
开发语言·后端·golang
Tairitsu_H4 小时前
[C++] 深入理解红黑树:封装set与map
开发语言·c++·set·map·红黑树·模拟实现
泡海椒4 小时前
JQuick-Curl 性能分析:并发场景下的性能表现与调优,第三方接口调用不只要快写也要稳跑
java·开发语言·okhttp