跳至主要內容

设计模式

星星大约 3 分钟

设计模式

单例模式

  • 定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点
  • 实现:用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象
var Singleton = function (name) {
    this.name = name
}
Singleton.prototype.getName = function () {
    alert(this.name)
}
Singleton.getInstance = (function (name) {
    var instance = null
    return function (name) {
        if (!instance) {
            instance = new Singleton(name)
        }
        return instance
    }
})()
var a = Singleton.getInstance('sven1')
var b = Singleton.getInstance('sven2') // 已存在instance,直接返回sven1
alert(a === b) // true
  • 惰性单例模式,在调用时创建实例
var getSingle = function (fn) {
    var result
    return function () {
        return result || (result = fn.apply(this, arguments)) // 如果存在实例,直接返回
    }
}

// 点击按钮,出现弹窗,重复点击,支出现一次
var createLoginLayer = function () {
    var div = document.createElement('div')
    div.innerHTML = '我是登录浮窗'
    div.style.display = 'none'
    document.body.appendChild(div)
    return div
}
var createSingleLoginLayer = getSingle(createLoginLayer)
document.getElementById('loginBtn').onclick = function () {
    var loginLayer = createSingleLoginLayer()
    loginLayer.style.display = 'block'
}

发布-订阅模式(观察者模式)

  • 对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知

  • eg:售楼信息

    var salesOffices = {} // 定义售楼处
    salesOffices.clientList = {} // 缓存列表,存放订阅者的回调函数
    salesOffices.listen = function (key, fn) {
        if (!this.clientList[key]) {
            this.clientList[key] = [] // 如果还没有订阅过此类消息,给该类消息创建一个缓存列表
        }
        this.clientList[key].push(fn) // 订阅的消息添加进消息缓存列表
    }
    salesOffices.trigger = function () {
        // 发布消息
        var key = Array.prototype.shift.call(arguments) // 取出消息类型
        var fns = this.clientList[key] // 取出该消息对应的回调函数集合
        if (!fns || fns.length === 0) {
            // 如果没有订阅该消息,则返回
            return false
        }
        for (var i = 0, fn; (fn = fns[i++]); ) {
            fn.apply(this, arguments) // (2) // arguments 是发布消息时附送的参数
        }
    }
    salesOffices.listen('squareMeter88', function (price) {
        // 小明订阅 88 平方米房子的消息
        console.log('价格= ' + price) // 输出: 2000000
    })
    salesOffices.listen('squareMeter110', function (price) {
        // 小红订阅 110 平方米房子的消息
        console.log('价格= ' + price) // 输出: 3000000
    })
    salesOffices.trigger('squareMeter88', 2000000) // 发布 88 平方米房子的价格
    salesOffices.trigger('squareMeter110', 3000000) // 发布 110 平方米房子的价格
    
  • 通用的发布订阅模式,全局 Event

      var event = {
          clientList: [],
          listen: function( key, fn ){
              if ( !this.clientList[ key ] ){
                  this.clientList[ key ] = [];
              }
              this.clientList[ key ].push( fn );// 订阅的消息添加进消息缓存列表
          },
          trigger:function(){
              var key = Array.prototype.shift.call( arguments ) // (1);
              var fns = this.clientList[ key ];
              if ( !fns || fns.length === 0 ){ // 如果没有绑定对应的消息
                  return false;
              }
              for( var i = 0, fn; fn = fns[ i++ ]; ){
                  fn.apply( this, arguments ); // (2) // arguments 是 trigger 时带上的参数
              }
          },
          remove:function(key,fn){
              var fns = this.clientList[key]
              if(!fns){ // 如果 key 对应的消息没有被人订阅,则直接返回
                  return false
              }
              if(!fn){ // 如果没有传入具体的回调函数,表示需要取消 key 对应消息的所有订阅
                  fns && fns.length = 0
              }else{
                  for ( var l = fns.length - 1; l >=0; l-- ){ // 反向遍历订阅的回调函数列表
                      var _fn = fns[l]
                      if( _fn === fn){
                          fns.splice(l,1) // 删除订阅者的回调函数
                      }
                  }
              }
          }
      };
    
      var installEvent = function( obj ){ // 给所有的对象都动态安装发布—订阅功能
          for ( var i in event ){
              obj[ i ] = event[ i ];
          }
      };
    
      var salesOffices = {};
      installEvent( salesOffices );
    
    
      salesOffices.listen( 'squareMeter88', fn1 = function( price ){ // 小明订阅消息
          console.log( '价格= ' + price );
      });
      salesOffices.listen( 'squareMeter100', fn2 = function( price ){ // 小红订阅消息
          console.log( '价格= ' + price );
    
    
      });
      //salesOffices.remove( 'squareMeter88', fn1 ); // 删除小明的订阅
      salesOffices.trigger( 'squareMeter88', 2000000 ); // 输出:2000000
      salesOffices.trigger( 'squareMeter100', 3000000 ); // 输出:3000000
    
    
上次编辑于:
贡献者: wanghongjie