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);
    };
    /**
     * 这里可以看出每个对象之间的耦合性很小。
     */
  • 相关阅读:
    一文读懂网管协议
    Python 3.8 离线安装
    Redis 6.X 离线安装
    ES 日期格式影响聚合效果
    (1)Canal入门
    (10)MySQL进阶篇SQL优化(InnoDB锁-间隙锁)
    (9)MySQL进阶篇SQL优化(InnoDB锁-记录锁)
    (8)MySQL进阶篇SQL优化(InnoDB锁-共享锁、排他锁与意向锁)
    (7)MySQL进阶篇SQL优化(InnoDB锁-事务隔离级别 )
    (6)MySQL进阶篇SQL优化(MyISAM锁)
  • 原文地址:https://www.cnblogs.com/stinchan/p/7057968.html
Copyright © 2011-2022 走看看