js设计模式学习笔记(十七):中介者模式

196 阅读2分钟

中介者模式

特点

  • 比较像 发布-订阅者模式(观察者模式),但是区分作用对象仍有一定却别。
  • 将对象之间解耦,尽量避免基础对象的直接调用,将对象的变化监控并通知给其他对象。
  • 中介者模式是针对于多对象多状态多变化的一种代码优化设计模式。因为需要提供多对象的中介者枢纽,
  • 反而会占用额外的内存。若对象之间的通知与反馈较多且复杂频繁会导致中介者本身会有较大的内存消耗。

介绍

  • 基础对象,只需要考虑自己应该有的行为,对外界的影响全部交给中介者进行处理,自己只需要将自己发生的变化告诉中介者,不必考虑,自己的变化对于外界的影响。而对于外界的变化也依靠中介者进行提供,而不需要被其他基础对象通知,做到最少知识原则-迪米特法则。

  • 中介者负责接受各个对象发布的消息,并将对应的消息传达到另一方或者直接处理。

  • 具体去通知谁,所有的对外操作全部在中介者中完成。这时就会相对简单和方便管理

demo

更多详细代码

  • 设计如下场景
    • 多玩家,分两队。
    • 若全队死亡则为团灭,认输。提示游戏结束,并展示结果。
  • 若考虑玩家掉线,则还需要循环变量所有玩家进行通知。这在多对象多状态的情况下,每一个对象的一个状态改变都需要自己去通知其对象,这对于这个对象自身来说负荷太大,而且在任意状态都不可能是单一对象的单一变化。对于后期代码维护也是一项艰巨的任务。

// 玩家对象
function Player(name, teamColor, playerDirector) {
  this.name = name;
  this.teamColor = teamColor;
  this.state = "alive";
  this.playerDirector = playerDirector;
  this.playerDirector.ReceiveMessage("addPlayer", this);
}

Player.prototype.win = function () {
  console.log(`${this.name}'s team ${this.teamColor} is winner!`);
};

Player.prototype.lose = function () {
  console.log(`${this.name}'s team ${this.teamColor} is loser!`);
};

Player.prototype.die = function () {
  this.state = "die";
  this.playerDirector.ReceiveMessage("playerDie", this);
};

Player.prototype.outline = function () {
  this.state = "outline";
  this.playerDirector.ReceiveMessage("playerOutline", this);
};

Player.prototype.changeTeam = function (teamColor) {
  if (player.state === "die") {
    this.playerDirector.ReceiveMessage("playerchangeTema", teamColor, this);
    this.teamColor = teamColor;
  } else {
    console.log("角色未死亡,无法转换队伍");
  }
};

// 玩家中介者
function PlayerDirector() {
  this.playerList = {};
}

// 接收信息
PlayerDirector.prototype.ReceiveMessage = function () {
  const [messageType, ...params] = arguments;
  const fn = this[messageType];
  if (fn) {
    fn.apply(this, params);
  } else {
    throw new Error("无法处理此消息");
  }
  this[messageType];
};

// 添加玩家
PlayerDirector.prototype.addPlayer = function (player) {
  const team = this.playerList[player.teamColor];
  if (team) {
    team.push(player);
  } else {
    this.playerList[player.teamColor] = [player];
  }
};

// 玩家死亡
PlayerDirector.prototype.playerDie = function (player) {
  let team_all_die = true;
  const currentTeam = this.playerList[player.teamColor];
  for (let i of currentTeam) {
    if (i.state !== "die") {
      team_all_die = false;
      break;
    }
  }
  if (team_all_die) {
    for (let team of Object.values(this.playerList)) {
      for (let i of team) {
        if (i.teamColor === player.teamColor) {
          i.lose();
        } else {
          i.win();
        }
      }
    }
  }
};

// 玩家离线
PlayerDirector.prototype.playerOutline = function (player) {
  let team = this.playerList[player.teamColor];
  this.playerList[player.teamColor] = team.filter((i) => i !== player);
};

// 玩家变换队伍
PlayerDirector.prototype.playerchangeTema = function (newTeamColor, player) {
  this.playerOutline(player);
  this.addPlayer(player);
};

// 玩家工厂
const PlayerFactory = (function () {
  let playerDirector = null;
  return function (name, teamColor) {
    if (!playerDirector) {
      playerDirector = new PlayerDirector();
    }
    return new Player(name, teamColor, playerDirector);
  };
})();

const player1 = PlayerFactory("player1", "red");
const player2 = PlayerFactory("player2", "blue");
const player3 = PlayerFactory("player3", "blue");

player3.outline();
player1.die();