javascript优化--12模式(设计模式)03

观察者模式

通过创建一个可观察的对象,当发生一个感兴趣的事件时将该事件通告给所有观察者,从而形成松散的耦合

订阅杂志

//发布者对象
var publisher = {
  subscribers: {
    any: [] //事件类型
  },
  //将订阅者添加到subscribers数组;
  subscribe: function(fn, type) {
    type = type || 'any';
    if(typeof this.subscribers[type] === 'undefined') {
      this.subscribers[type] = [];
    }
    this.subscribers[type].push(fn);
  },
  //从订阅者数组中删除订阅者
  unsubscribe: function(fn, type) {
    this.visitSubscribers('publish', publication, type);
  },
  //遍历循环
  publish: function(publication, type) {
    this.visitSubscribers('publish', publication, type);
  },
  visitSubscribers: function(action, arg, type) {
    var pubtype = type || 'any',
    subscribers = this.subscribers[pubtype], i, max = subscribers.length;
    for(i = 0; i < max; i++) {
      if(action === 'publish') {
        subscribers[i](arg);  
      } else {
        if(subscribers[i] === arg) {
          subscribers.splice(i, 1);
        }
      }
    }
  }
}
//构造发行者
function makePublisher(o) {
  var i;
  for(i in publisher) {
    if(publisher.hasOwnProperty(i) && typeof publisher[i] === 'function') {
      o[i] = publisher[i];
    }
  }
  o.subscribers = {any: []};
}
//paper对象,发布日刊和月刊
var paper = {
  daily: function() {
    this.publish("big news today");
  },
  monthly: function() {
    this.publish("interesting analysis", "monthly");
  }
};
//订阅者joe
var joe = {
  drinkCoffee: function(paper) {
    console.log('Just read ' + paper);
  },
  sundayPreNap: function(monthly) {
    console.log('About to fall asleep reading this ' + monthly);
  }
}
//将paper构造成一个发行者
makePublisher(paper);
//joe订阅paper
paper.subscribe(joe.drinkCoffee);
paper.subscribe(joe.sundayPreNap, 'monthly');
//触发事件
paper.daily();
paper.daily();
paper.daily();
paper.monthly();
//扩展将joe为发布者
makePublisher(joe);
joe.tweet = function(msg) {
  this.publish(msg);
}
paper.readTweets = function(tweet) {
  alert('Call big meeting! Someone ' + tweet);
}
joe.subscribe(paper.readTweets);

joe.tweet('hated the paper today');


按键游戏

var publisher = {
  subscribers: {
    any: []
  },
  on: function (type, fn, context) {
    type = type || 'any';
    fn = typeof fn === "function" ? fn : context[fn];    
    if (typeof this.subscribers[type] === "undefined") {
      this.subscribers[type] = [];
    }
    this.subscribers[type].push({fn: fn, context: context || this});
  },
  remove: function (type, fn, context) {
    this.visitSubscribers('unsubscribe', type, fn, context);
  },
  fire: function (type, publication) {
    this.visitSubscribers('publish', type, publication);
  },
  visitSubscribers: function (action, type, arg, context) {
    var pubtype = type || 'any',
    subscribers = this.subscribers[pubtype], i,
    max = subscribers ? subscribers.length : 0;
            
    for (i = 0; i < max; i += 1) {
      if (action === 'publish') {
        subscribers[i].fn.call(subscribers[i].context, arg);
      } else {
        if (subscribers[i].fn === arg && subscribers[i].context === context) {
          subscribers.splice(i, 1);
        }
      }
    }
  }
};

function makePublisher(o) {
  var i;
  for (i in publisher) {
    if (publisher.hasOwnProperty(i) && typeof publisher[i] === "function") {
      o[i] = publisher[i];
    }
  }
  o.subscribers = {any: []};
}

var game = {  
  keys: {},
  addPlayer: function (player) {
    var key = player.key.toString().charCodeAt(0);
    this.keys[key] = player;
  },
  handleKeypress: function (e) {
    e = e || window.event; // IE
    if (game.keys[e.which]) {
      game.keys[e.which].play();
    }
  },
  handlePlay: function (player) {
    var i, players = this.keys, score = {};
    for (i in players) {
      if (players.hasOwnProperty(i)) {
        score[players[i].name] = players[i].points;
      }
    }
    this.fire('scorechange', score);
  }
};

function Player(name, key) {
  this.points = 0;
  this.name = name;
  this.key  = key;
  this.fire('newplayer', this);
}

Player.prototype.play = function () {
  this.points += 1;
  this.fire('play', this);
};

var scoreboard = {  
  element: document.getElementById('results'),  
  update: function (score) { 
    var i, msg = '';
    for (i in score) {
      if (score.hasOwnProperty(i)) {
          msg += '<p><strong>' + i + '</strong>: ';
          msg += score[i];
          msg += '</p>';
      }
    }
    this.element.innerHTML = msg;
  }
};

makePublisher(Player.prototype);
makePublisher(game);

Player.prototype.on("newplayer", "addPlayer", game);
Player.prototype.on("play",      "handlePlay", game);

game.on("scorechange", scoreboard.update, scoreboard);

window.onkeypress = game.handleKeypress;

var playername, key;
while (1) {
  playername = prompt("Add player (name)");
  if (!playername) {
    break;
  }
  while (1) {
    key = prompt("Key for " + playername + "?");
    if (key) {
      break;
    }
  }
  new Player(playername,  key);    
}

原文地址:https://www.cnblogs.com/jinkspeng/p/4343716.html