中介者模式:程序界的代工厂

前言

中介这个词相信你肯定不陌生,这个模式在我们的日常生活当中太常见了,比如:领导跟你说帮完处理下某事,你收到通知后就马上去做了,领导不关心在这个过程当中你多少个日夜没睡,他关心的只是结果。作为领导的下属你就应该有求必应,替领导完成所要完成的一些事。在这里中介事是谁,当然是你拉!领导-你-事情,你帮领导去做某事情。在程序中中介者模式也差不多这个意思。我只需要跟你说我要做什么,你(中介者)替我完成就可以。

为什么要中介者模式

中介者模式相当于把程序中的一事有共性的东西(行为)抽出来,封装到一个对象中。然后其它对象如果需要作这方面的处理,就可以只需要向它发号施令就可以了,它就会替你完成。这样封装在对象中的一些共享行为对于那些有相同行为需要的对象来说就不需要自己持有这些方法,如果对象有很多,每一个对象都有一个自己的方法,那代理得有多少代码,看着都累。

如果要改动、删除或者添加对象的某些方法,运气好的话,可能就只需要修改一个对象(特有),如果运气不佳(共有),那你就只能自认倒霉,所有对象都得动一遍,你知道敲代码不是体力活,而是脑力活,请把时间用在点子上。

中介者模式代码示例

下面我们就以最近很火的绝地求生游戏为例子,来做一个简单的例子。

简单地实现模式选择,玩家添加及分队,玩家死亡,玩家掉线,请看码:

var tertiumQuid = (function () {
    var teams = {},
        mode = 1,
        tempId = 1;
    operations = {
        playMode: function (m) {
            mode = m;
        },
        addPlayer: function (player) {
            var teamId = Math.ceil(tempId / mode); // 根据模式获取队伍的 ID
            if (!teams[teamId]) { // 如果队伍不存在,创建队伍
                teams[teamId] = [];
            }
            player.teamId = teamId;
            teams[teamId].push(player); // 入队伍里添加玩家
            tempId++;
        },
        playerDead: function (player) {
            var playerTempId = player.teamId,
                playerTeam = teams[playerTempId],
                game_over = true,
                keyArray = [];
            for (var i = 0, item; item = playerTeam[i++];) { // 遍历阵亡玩家所对应的队伍
                if (item.state === "alive") {
                    game_over = false;
                    break;
                }
            }
            if (game_over) { // 如果全队阵亡,游戏结束
                for (var j = 0, itemJ; itemJ = playerTeam[j++];) {
                    itemJ.lose();
                }
                delete teams[playerTempId]; // 从存活队列中删除
            }
            for (var key in teams) {
                keyArray.push(key);
            }
            if (keyArray.length === 1) { // 如果只剩下一队
                for (var k = 0, itemK; itemK = teams[keyArray][k++];) { // 通知获胜队伍所有玩家
                    itemK.win();
                }
            }
        },
        offline: function (player) {
            var playerTempId = player.teamId,
                playerTeam = teams[playerTempId];
            for (var i = 0, item; item = playerTeam[i++];) { // 遍历阵亡玩家所对应的队伍
                if (item.online && item.state === "alive") { // 在线并且还没阵亡的玩家
                    item.offline(player);
                }
            }
        }
    };
    return {
        receiver: function () {
            var _shift = Array.prototype.shift;
            var handle = _shift.call(arguments);
            operations[handle].apply(this, arguments);
        }
    };
})();

// 定义玩家类
var Player = function (name) {
    this.name = name;
    this.teamId = null;
    this.online = true;
    this.state = "alive";
    tertiumQuid.receiver("addPlayer", this); // 新增玩家添加到玩家列表
};
Player.prototype.offline = function (player) {
    player.online = false;
    console.log("大家不要想" + player.name + ",他掉线了!");
};
Player.prototype.die = function () {
    this.state = "dead";
    console.log(this.name + "你已阵亡!");
    tertiumQuid.receiver('playerDead', this);
};
Player.prototype.lose = function () {
    console.log(this.name + "大吉大利,再接再厉!");
};
Player.prototype.win = function () {
    console.log(this.name + "大吉大利,今晚吃鸡!");
};

/*************************** 下面是用法 ***************************/
// 模式
var mode = {
    single: 1,
    double: 2,
    quad: 4
};

// 设置游戏模式
tertiumQuid.receiver("playMode", mode["quad"]);
// 创建游戏用户
var player1 = new Player("player1"),
    player2 = new Player("player2"),
    player3 = new Player("player3"),
    player4 = new Player("player4"),
    player5 = new Player("player5"),
    player6 = new Player("player6"),
    player7 = new Player("player7"),
    player8 = new Player("player8"),
    player9 = new Player("player9");

// 手动设置用户掉线
tertiumQuid.receiver("offline", player8);

// 人为地让玩家阵亡
player5.die();
player6.die();
player7.die();
player8.die();
player9.die();

/*************************** 输出结果 ***************************/
// 大家不要想player8,他掉线了!
// player5你已阵亡!
// player6你已阵亡!
// player7你已阵亡!
// player8你已阵亡!
// player5大吉大利,再接再厉!
// player6大吉大利,再接再厉!
// player7大吉大利,再接再厉!
// player8大吉大利,再接再厉!
// player9你已阵亡!
// player9大吉大利,再接再厉!
// player1大吉大利,今晚吃鸡!
// player2大吉大利,今晚吃鸡!
// player3大吉大利,今晚吃鸡!
// player4大吉大利,今晚吃鸡!