阅读 435

从游戏角度看发布-订阅者模式

本文档已更新于 【前端橘子君】 【Github】

描述对象间一对多的关系,当一个状态改变时,所有依赖于它的对象都能够得到通知并更新。

从概念上来说,发布-订阅者模式只是观察者模式的一种优化方案,他们都是描述对象间一对多的关系,如果有一个状态改变,则所有依赖于它的对象都会得到更新。

见的最多的就是vue中的实现原理。

先回顾一下观察者模式中创建副本的例子。

// 观察者模式
// 目标(被观察者)
class Team {
	constructor(fbName, player) {
	  // 定义一个列表来表示一个队伍
		this.list = [];
		// 自己需要占一个位置
		this.list.push(player);
	}
	// 开启副本
	start () {
		console.log('队伍人数达标,可以开启副本了')
		// 通知队员,副本开启
		this.list.map(ele => ele.start())
	}
	// 增加队员
	add (player) {
    this.list.push(player);
    // 人数达标,通知队员准备
		if (this.list.length === 5) {
			this.start();
		}
	}
	// 踢出队员
	remove (player) {
		console.log(`${player.name}实力不够,踢出队伍`)
		// 找到这个人在队伍中的位置
		let index = this.list.indexOf(player)
		// 踢出队伍
		this.list.splice(index, 1);
	}
}

// 观察者(玩家)
class Player {
	constructor(name) {
		// 定义一个玩家
	  this.name = name;
  }

  add (army) {
    // 加入某个队伍
    army.add(this)
  }

  // 确认开启副本功能
	start () {
		console.log(`${this.name}已经点击了确认,随时可以开启副本`)
	}
}

// 创建玩家
let player1 = new Player('赵一')
let player2 = new Player('钱二')
let player3 = new Player('孙三')
let player4 = new Player('李四')
let player5 = new Player('周五')
let player6 = new Player('吴六')

// 明确副本名称,以及确定队长
let team = new Team('大闹天宫副本', player1);

// 添加队员
player2.add(team)
player3.add(team)
team.remove(player2)
player4.add(team)
player5.add(team)
player6.add(team)
复制代码

这里可以看到,观察者模式的任务中心其实是在目标(被观察者)内部,观察者和目标(被观察者)中间虽然说实现了松耦合,但是还是存在一定的直接关联,而发布-订阅者模式的任务中心是放在调度中心,观察者(订阅者)和被观察者(发布者)并没有直接的关联,或者说这两者没有耦合关系。

发布-订阅者模式中的耦合只存在于发布者-调度中心、订阅者-调度中心之间。

新增任务大厅

将上边的游戏副本模式修改一下,副本组队不再需要队长组队了,队长在只需任务大厅启动一个副本团队任务,然后就可以做其他事情了,其他玩家在任务大厅中响应任务大厅中的团队任务,队长确认并人数达标后就可以开启副本了。

// 发布-订阅者模式
// 调度中心
class TaskCenter {
  // 创建任务大厅
  constructor () {
    // 创建任务面板
    this.list = {};
  }
  create (name, team) {
    // 创建任务面板
    this.list[name] = {};
    this.list[name].team = team;
  }
  // 创建副本
  add (name, player) {
    // 创建者即为团队的第一个人
    this.list[name].team.add(player);
  }
  start (name) {
		this.list[name].team.list.forEach(ele => ele.start())
	}
}
// 实例化调度中心
var taskCenter = new TaskCenter();
复制代码

创建玩家

// 订阅者(玩家)
class Player {
	constructor(name) {
		// 定义一个玩家
	  this.name = name;
  }

  add (name) {
    // 加入某个队伍
    taskCenter.add(name, this)
  }

  // 确认开启副本功能
	start () {
		console.log(`${this.name}已经点击了确认,随时可以开启副本`)
	}
}

// 实例化玩家
let player1 = new Player('赵一')
let player2 = new Player('钱二')
let player3 = new Player('孙三')
let player4 = new Player('李四')
let player5 = new Player('周五')
let player6 = new Player('吴六')
复制代码

创建团队

// 发布者(团队)
class Team {
  constructor (creater, name) {
    this.list = [];
    this.name = name;
    this.add(creater)
  }
  // 添加成员
  add (player) {
    this.list.push(player);
    // 当团队玩家数量达标,则团队通知成员准备进入副本
    if (this.list.length === 5) {
			taskCenter.start(this.name);
		}
  }
}
复制代码

开始游戏

// 创建副本
let name = Symbol('大闹天宫');

// 实例化团队
let team = new Team(player1, name);

taskCenter.create(name, team);

// 队员加入副本
taskCenter.add(name, player2);
taskCenter.add(name, player3);
player5.add(name);
taskCenter.add(name, player4);
复制代码

解析

从上面的代码可以看到,团队(发布者)和玩家(订阅者)之间并没有直接关联,而是通过任务大厅的任务面板(调度中心)将两者联系起来的,包括新增队员和开启副本都是通过taskCenter.add()taskCenter.start()触发的,这样的话发布者和订阅者中间并没有直接关联,这样就做到了两者之间的零耦合。

对比观察者模式,发布-订阅者模式和观察者模式的最大区别在于:

  • 观察者模式的任务中心在目标(被观察者)内部
  • 发布-订阅者模式的任务中心是放在调度中心
  • 观察者模式中,观察者和目标之间实现了松耦合
  • 发布-订阅者模式中,订阅者和发布者之间实现了零耦合

更多相关文档,请见:

线上地址 【前端橘子君】

GitHub仓库【前端橘子君】

文章分类
前端
文章标签