JavaScript设计模式——中介者模式(Mediator Pattern)

82 阅读3分钟

八、中介者模式(Mediator Pattern)

1.概念介绍

中介者模式(Mediator Pattern) 是用来降低多个对象和类之间的通信复杂性,促进形成松耦合,提高可维护性。

在这种模式下,独立的对象之间不能直接通信,而是需要中间对象( mediator对象),当其中一个对象( colleague对象)状态改变后,它会通知 mediator对象, 然后 mediator对象会把该变换通知到任意需要知道此变化的 colleague对象。

2.优缺点和应用场景

2.1优点

  • 降低类的复杂度,从一对多转成一对一。
  • 为各个类之间解耦。
  • 提高代码可维护性。

2.2缺点

中介者会越来越庞大,变得难以维护。

2.3应用场景

  • 系统中对象之间存在比较复杂的引用关系,而且难以复用该对象。
  • 需要生成最少的子类,实现一个中间类封装多个类中的行为的时候。

另外: 不要在职责混乱的时候使用。

3.基本案例

这里我们实现一个简单的案例,一场测试结束后,公布结果,告知解答出题目的人挑战成功,否则挑战失败:
这个案例来自JavaScript 中常见设计模式整理

const player = function(name) {
    this.name = name;
    playerMiddle.add(name);
}
player.prototype.win = function() {
    playerMiddle.win(this.name);
}
player.prototype.lose = function() {
    playerMiddle.lose(this.name);
}
const playerMiddle = (function() { // 将就用下这个 demo,这个函数当成中介者
    const players = [];
    const winArr =  [];
    const loseArr = [];
    return {
        add: function(name) {
            players.push(name)
        },
        win: function(name) {
            winArr.push(name)
            if (winArr.length + loseArr.length === players.length) {
                this.show()
            }
        },
        lose: function(name) {
            loseArr.push(name)
            if (winArr.length + loseArr.length === players.length) {
                this.show()
            }
        },
        show: function() {
            for (let winner of winArr) {
                console.log(winner + '挑战成功;')
            }
            for (let loser of loseArr) {
                console.log(loser + '挑战失败;')
            }
        },
    }
}())

const a = new player('A 选手');
const b = new player('B 选手');
const c = new player('C 选手');
a.win();
b.win();
c.lose();

// A 选手挑战成功;

// B 选手挑战成功;

// C 选手挑战失败;

4.书本案例

这里的中介者需要知道所有其他对象信息,并且它需要知道哪个玩家点击了一次,随后通知玩家。玩家进行游戏的时候,还要通知中介者它做的事情,中介者更新分数并显示比分。

这里的 player对象都是通过 Player()构造函数生成,并且都有 points和 name属性,每次调用 play()都会增加1分并通知中介者。

function Player(name){
    this.points = 0;
    this.name   = name;
}

Player.prototype.play = function(){
    this.points += 1;
    mediator.played();
}

计分板有个 update()方法,当玩家回合结束就会调用,它不知道任何玩家的信息也没有保存分值,只是实现展示当前分数。

let scoreboard = {
    // 待更新HTML元素
    ele: document.getElementById('result');
    // 更新比分
    update: function (score){
        let msg = '';
        for(let k in score){
            if(score.hasOwnProperty(k)){
                msg = `<p>${k} : ${score[k]}</p>`
            }
        }
        this.ele.innerHTML = msg;
    }
}

接下来创建 mediator对象:

let mediator = {
    players: {},       // 所有玩家
    setup: function(){ // 初始化
        let players = this.players;
        players.homw = new Player('Home');
        players.guest = new Player('Guest');
    },
    // 当有人玩时 更新分数
    played: function(){
        let players = this.players 
        let score = {
            Home: players.home.points,
            Guest: players.guest.points,
        }
        scoreboard.update(score);
    },
    // 处理用户交互
    keypress: function(e){
        e = e || window.event;  // 兼容IE
        if(e.which === 49){     // 按键1
            mediator.players.home.play();
        }
        if(e.which === 48){     // 按键0
            mediator.players.guest.play();
        }
    }
}

最后就是需要运行和卸载游戏了:

mediator.setup();
window.onkeypress = mediator.keypress;
// 游戏30秒后结束
setTimeout(function(){
    window.onkeypress = null;
    alert('游戏结束');
}, 30000)

参考资料

  1. 《JavaScript Patterns》
  2. 《JavaScript 高级应用程序设计》