javascript 设计模式之观察者模式

2,090 阅读4分钟

文章系列

javascript 设计模式之单例模式

javascript 设计模式之适配器模式

javascript 设计模式之装饰者模式

javascript设计模式之代理模式

javascript 适配、代理、装饰者模式的比较

javascript 设计模式之状态模式

javascript 设计模式之迭代器模式

javascript 设计模式之策略模式

javascript 设计模式之观察者模式

javascript 设计模式之发布订阅者模式

什么是观察者模式

观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。 —— Graphic Design Patterns

观察者模式

生活中的观察者模式

小明最近看中了一个楼盘,到了售楼处之后才被告知,该楼盘的房子还未开盘,具体开盘时间还没定。除了小明,一起来的还有小红,小二人,为了第一时间得知楼盘开盘时间,他们都把电话号码留给了销售员王五,王五也答应楼盘一开盘就会发消息通知他们。

过了不久,新楼盘开盘时间定了,王五赶紧拿出花名册,遍历上面的号码,群发了短信通知了他们。

至于这些人收到通知是选择走路来、开车来、或者不来就自行决定了

重点概念对号入座:

观察者模式有个"别名",叫发布-订阅模式(两者还是有些不一样,具体看)。这个别名非常形象诠释了观察者模式里的两个核心的角色要求:发布者与订阅者。将生活中的这个案例对号入座如下:

发布者: 王五

订阅者: 小明、小红,小二

订阅事件: 小明、小红、小二将号码留在售楼部

通知变化: 王五群发短信通知他们

自定义观察者模式

经过上面的分析,该模式要创建两个类,一个是代表发布者,起名 Subject,另一个是代表订阅者,起名 Observer 。 这个类应该要有哪些功能呢?大家看下上文中的王五有什么操作?

  • 登记小明、小红、小二的号码(增加订阅者)
  • 群发短信通过小明、小红、小二(通知订阅者)
  • 另外作为销售员,还应该具有删除某些人的权限吧(比如小明答复说已经不买了,那这时就可以考虑将他从花名册去删除) 根据上面的分析,写出如下代码:
// 定义发布者类
class Subject {
  constructor() {
    this.observers = []
    console.log('Subject created')
  }
  // 增加订阅者
  add(observer) {
    console.log('Subject.add invoked')
    this.observers.push(observer)
  }
  // 移除订阅者
  remove(observer) {
    console.log('Subject.remove invoked')
    this.observers.forEach((item, i) => {
      if (item === observer) {
        this.observers.splice(i, 1)
      }
    })
  }
  // 通知所有订阅者
  notify() {
    console.log('Publisher.notify invoked')
    this.observers.forEach((observer) => {
      observer.update(this)
    })
  }
}

再来看下订阅者具备的功能,小明有啥能力呢?

  • 被通知楼盘开盘
// 定义订阅者类
class Observer {
    constructor() {
      console.log('Observer created')
    }
    update() {
      console.log('Observer.update invoked')
    }
}

上面定义的就是最基本的观察者模式的两个类。在实际的业务开发中,定制化的发布者/订阅者都可以继承这两个基本来扩展。比如现在有个需求是监听楼盘开盘与否的变化。代码如下:

// 定义个具体的销售员发布类
class SalesPublisher extends Subject {
	constructor() {
		super()
		// 楼盘起初是还未开盘
		this.state = 'close'
		// 还没将人员号码登记
		this.observers = []
	}
	// 获取当前楼盘状态
	getState() {
		return this.state
	}
	// 设置楼盘状态
	setState(state) {
		console.info('楼盘开盘了')
		this.state = state
		// 楼盘状态一改, 通知要购买房子的人
		this.notify()
	}
}

作为购房者

// 购房子类
class BuyerObserver extends Observer {
	constructor(name) {
		super()
		this.name = name
	}

	// 重写一个具体的 update 方法
	update(publisher) {
		// 获取楼盘的状态
		let state = publisher.getState()
		console.info(`${this.name} update, state: ${state}`)
		this.doSomething()
	}
	// 接收到消息之后,后续要处理的逻辑,比如回复销售员收到,开始筹钱等等
	doSomething() {
		console.info('开始筹钱')
	}
}

下面,让我们来检验下该代码是否能够正常? 何为正常:就是当楼盘状态更改时,都会紧接着调用 notify 方法来通知所有购房者,也就实现了定义里所谓的:

目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。

// 创建订阅者: 小明
const xiaoMing = new BuyerObserver('小明')
// 创建订阅者: 小红
const xiaoHong = new BuyerObserver('小红')
// 创建订阅者: 小二
const xiaoEr = new BuyerObserver('小二')

// 创建发布者: 王五
const wangwu = new SalesPublisher()

// 开始添加购房者的号码
wangwu.add(xiaoMing)
wangwu.add(xiaoHong)
wangwu.add(xiaoEr)

// 楼盘开盘了,是时候通知购房者了
wangwu.setState('open')

以上,就是一个观察者模式实现过程

参考链接

JavaScript 设计模式核⼼原理与应⽤实践

结语

下一篇将会讲到发布-订阅者模式。 你的点赞是对我最大的肯定,如果觉得有帮助,请留下你的赞赏,谢谢!!!

本文代码