zoukankan      html  css  js  c++  java
  • JavaScript设计模式_11_中介者模式

      在我们生活的世界中,每个人每个物体之间都会产生一些错综复杂的联系。在应用程序里也是一样,程序由大大小小的单一对象组成,所有这些对象都按照某种关系和规则来通信。

    如下图1所示:

    图1

      中介者模式的作用就是解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的相关对象都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介者对象即可。中介者使各对象之间耦合松散,而且可以独立地改变它们之间的交互。中介者模式使网状的多对多关系变成了相对简单的一对多关系。

    如下图2所示:

    图2

    /**
     * pre:中介者模式
     * 在生活中,每个人每个物体之间都会产生错综复杂的联系。中介者的作用就是解除对象与对象之间的紧耦合。增加一个中介者之后,
     * 所有的对象都通过中介者通信,而不是互相引用。当一个对象发生变化时,只需要通知中介者即可。
     */
    // --------- 示例1 ---------
    /**
     * 两个玩家  - 对战
     * 定义win、lose、die
     */
    var Player = function(name) {
        this.name = name;
        this.enemy = null;
    };
    Player.prototype.win = function() {
        console.log(this.name + ":won.");
    };
    Player.prototype.lose = function() {
        console.log(this.name + ":lost.");
    };
    Player.prototype.die = function() {
        this.lose();
        this.enemy.win();
    };
    
    var player1 = new Player("xiaoming");
    var player2 = new Player("xiaowang");
    player1.enemy = player2;
    player2.enemy = player1;
    
    player1.die();
    //---------- 示例2 -----------
    /**
     * 多个玩家 - 对战
     * partners = [] 和 enemies = []
     */
    var Player = function(name, teamColor) {
        this.partners = [];
        this.enemies = [];
        this.state = 'alive';
        this.name = name;
        this.teamColor = teamColor;
    };
    Player.prototype.lose = function() {
        console.log(this.name + ": lost.");
    };
    Player.prototype.win = function() {
        console.log(this.name + ":won.");
    };
    Player.prototype.die = function() {
        var all_dead = true;
        this.state = "dead";
        for(var a of this.partners) {
            if("dead" !== a.state) {
                all_dead = false;
                break;
            }
        }
        if(all_dead) {
            this.lose();
            for(var a of this.partners) {
                a.lose();
            }
            for(var b of this.enemies) {
                b.win();
            }
        }
    };
    // -- 玩家工厂 --
    var players = []; // 存放所有玩家
    var PlayerFactory = function(name, teamColor) {
        var newPlayer = new Player(name, teamColor);
        for(var i = 0, a; a = players[i++];) {
            if(a.teamColor === newPlayer.teamColor) {
                a.partners.push(newPlayer);
                newPlayer.partners.push(a);
            } else {
                a.enemies.push(newPlayer);
                newPlayer.enemies.push(a);
            }
        }
        players.push(newPlayer);
        return newPlayer;
    };
    
    var player1 = PlayerFactory("player1", "red"),
        player2 = PlayerFactory("player2", "red"),
        player3 = PlayerFactory("player3", "red"),
        player4 = PlayerFactory("player4", "red");
        
    var player5 = PlayerFactory("player5", "blue"),
        player6 = PlayerFactory("player6", "blue"),
        player7 = PlayerFactory("player7", "blue"),
        player8 = PlayerFactory("player8", "blue");
        
    player1.die();
    player2.die();
    player3.die();
    player4.die();
    //------------ 示例3 --------------
    /**
     * 上述代码,我们将partners和enemies作为玩家的属性,每当玩家有什么动作,比如角色移动、吃到道具、玩家死亡,
     * 我们都要显示的遍历其他对象。现在只是两个队,如果有成千上万的玩家,几十个队伍,如果有一个人掉线,就必须从
     * 所有的玩家以及敌人列表中移除。如果有解除队伍,加入别的队伍的功能,就不是循环解决的问题了。
     * 下面使用中介者模式重构代码:
     */
    var Player = function(name, teamColor) {
        this.name = name;
        this.teamColor = teamColor;
        this.state = "alive";
    };
    Player.prototype.lose = function() {
        console.log(this.name + ": lost.");
    };
    Player.prototype.win = function() {
        console.log(this.name + ": win.");
    };
    Player.prototype.die = function() {
        playerDirector.receiveMessage("playerDead", this);
    };
    Player.prototype.remove = function() {
        playerDirector.receiveMessage("playerRemove", this);
    };
    Player.prototype.changeTeam = function(color) {
        playerDirector.receiveMessage("changeTeam", this, color);
    };
    var playerDirector = (function() {
        var players = {},
            operations = {};
        operations.addPlayer = function(player) {
            var teamColor = player.teamColor;
            players[teamColor] = players[teamColor] || [];
            players[teamColor].push(player);
        };
        operations.playerRemove = function(player) {
            var teamColor = player.teamColor;
            var arr = players[teamColor];
            if(!arr || arr.length < 1) {
                return;
            }
            for(var i = 0, len = arr.length; i < len; i++) {
                if(arr[i] === player) {
                    arr.splice(i, 1);
                    break;
                }
            }
        };
        operations.changeTeam = function(player, newTeamColor) {
            operations.playerRemove(player);
            player.teamColor = newTeamColor;
            operations.addPlayer(player);
        };
        operations.playerDead = function(player) {
            var all_dead = true;
            var teamColor = player.teamColor,
                teamPlayers = players[teamColor];
            player.state = "dead";
            for(var a of teamPlayers) {
                if("dead" !== a.state) {
                    all_dead = false;
                    break;
                }
            }
            if(all_dead) {
                for(var a of teamPlayers) { // 本队队友全部死亡
                    a.lose();
                }
                for(var b in players) {
                    if(teamColor !== b) { // 告知敌人游戏胜利
                        for(var p of players[b]) {
                            p.win();
                        }
                    }
                }
            }
        };
        var receiveMessage = function() {
            var key = Array.prototype.shift.call(arguments);
            if(!operations[key]) {
                console.log("无效的命令:" + key);
                return;
            }
            operations[key].apply(this, arguments);
        };
        return {
            receiveMessage: receiveMessage
        }
    })();
    var PlayerFactory = function(name, color) {
        var player = new Player(name, color);
        playerDirector.receiveMessage("addPlayer", player);
        return player;
    };
    
    var player1 = PlayerFactory("player1", "red"),
        player2 = PlayerFactory("player2", "red"),
        player3 = PlayerFactory("player3", "red"),
        player4 = PlayerFactory("player4", "red");
        
    var player5 = PlayerFactory("player5", "blue"),
        player6 = PlayerFactory("player6", "blue"),
        player7 = PlayerFactory("player7", "blue"),
        player8 = PlayerFactory("player8", "blue");
        
    player1.changeTeam("blue");
    player2.die();
    player3.die();
    player4.die();
    //  ----------- 示例4 ---------------
    /**
     * 手机购买页面:
     * 用户选择颜色和输入数量,页面展示区展示选中的颜色和数量。
     */
    var goods = {
        "red": 3,
        "blue": 6
    };
    var colorSelect = document.getElementById("colorSelect");
    var numberInput = document.getElementById("numberInput");
    var colorInfo = document.getElementById("colorInfo");
    var numberInfo = document.getElementById("numberInfo");
    var btn = document.getElementById("cBtn");
    
    colorSelect.onchange = function() {
        var color = this.value;
        var stock = goods[color];
        var number = numberInput.value;
        colorInfo.innerHTML = this.selectedOptions[0].text;
        if(!color) {
            btn.disabled = true;
            btn.innerHTML = "请选择手机颜色";
            return;
        }
        if(!number || number < 1) {
            btn.disabled = true;
            btn.innerHTML = "请输入正确的购买数量";
            return;
        }
        if(number > stock) {
            btn.disabled = true;
            btn.innerHTML = "库存不足";
            return;
        }
        btn.disabled = false;
        numberInfo.innerHTML = number;
        btn.innerHTML = "放入购物车";
    };
    /**
     * 写完select的事件之后,还需要实现input框的事件。。
     * 试想,如果增加手机内存的选项,则需要增加的代码更多。
     * 这是因为,在实现中,每个节点对象都是耦合在一起的,改变或者增加一个对象,都要通知到其他对象。
     */
    //============= 示例5 ----------------
    /**
     * 增加内存选项,使用中介者改写代码
     */
    var goods = {
        "red|32": 10,
        "red|16": 0,
        "blue|32": 20,
        "blue|16": 1
    };
    var colorSelect = document.getElementById("colorSelect");
    var memorySelect = document.getElementById("memorySelect");
    var numberInput = document.getElementById("numberInput");
    var mediator = (function() {
        var colorInfo = document.getElementById("colorInfo");
        var memoryInfo = document.getElementById("memoryInfo");
        var numberInfo = document.getElementById("numberInfo");
        var btn = document.getElementById("cBtn");
        var changeEvent = function(obj) {
            var color = colorSelect.value;
            var memory = memorySelect.value;
            var number = numberInput.value;
            if(obj === colorSelect) {
                colorInfo.innerHTML = color;
            } else if(obj === memorySelect) {
                memoryInfo.innerHTML = memory;
            } else if(obj === numberInput) {
                numberInfo.innerHTML = number;
            }
            if(!memory) {
                btn.disabled = true;
                btn.innerHTML = "请选择内存."
                return;
            }
            if(!number || number < 1) {
                btn.disabled = true;
                btn.innerHTML = number ? "请输入正确的购买数量" : "请输入购买数量";
                return;
            }
            // 判断库存
            var stock = goods[color + "|" + memory];
            if(number > stock) {
                btn.disabled = true;
                btn.innerHTML = "库存不足";
                return;
            }
            btn.disabled = false;
            btn.innerHTML = "放入购物车";
        };
        return {
            change: changeEvent
        }
    })();
    colorSelect.onchange = function() {
        mediator.change(this);
    };
    memorySelect.onchange = function() {
        mediator.change(this);
    };
    numberInput.oninput = function() {
        mediator.change(this);
    };
    /**
     * 这里可以看出每个对象之间的耦合性很小。
     */
  • 相关阅读:
    Core Animation 文档翻译—附录C(KVC扩展)
    Core Animation 文档翻译—附录B(可动画的属性)
    Core Animation 文档翻译—附录A(Layer样貌相关属性动画)
    Core Animation 文档翻译 (第八篇)—提高动画的性能
    Core Animation 文档翻译 (第七篇)—改变Layer的默认动画
    Core Animation 文档翻译 (第六篇)—高级动画技巧
    Core Animation 文档翻译 (第五篇)—构建Layer的层次结构
    用Markdown快速排版一片文章
    Core Animation 文档翻译 (第四篇)—让Layer的content动画起来
    Core Animation 文档翻译(第三篇)—设置Layer对象
  • 原文地址:https://www.cnblogs.com/stinchan/p/7057968.html
Copyright © 2011-2022 走看看