基础模式
图解
思路解读
-
被观察对象
-
- 可以输入信息、更新信息
- 接受观察者的注册
- 更新消息推送给已注册的观察者集合
-
观察对象
-
- 接收被观察者推送的更新消息
例子分析
被观察对象
/**
* 信息输入类
* 被观察对象
*/
class LoginBean {
messageObj
loginEventListener
// 注册
addLoginEventListener = function (loginEventListener) {
this.loginEventListener = loginEventListener
}
// 通知
fireLoginEvent = function () {
this.loginEventListener.validateLogin(this.messageObj)
}
// 信息输入
inputMessage = function (userName, password) {
this.messageObj = { userName, password }
this.fireLoginEvent()
}
}
观察对象
/**
* 信息校验类
* 观察对象
*/
class LoginValidatorA {
// 接受信息并进行校验
validateLogin = function(event) {
if(!event.userName){
console.log('请输入名字')
}
else if(!event.password) {
console.log('请输入密码')
}
else {
console.log('输入成功', event.password, event.userName)
}
}
}
Main
// 实例化被观察对象
const loginBean = new LoginBean()
// 实例化观察对象
const loginValidator = new LoginValidatorA()
// 观察对象注册到被观察者对象中
loginBean.addLoginEventListener(loginValidator)
// 被观察对象更新数据
loginBean.inputMessage('你的名字', '123456')
全部代码
/**
* 信息输入类
* 被观察对象
*/
class LoginBean {
messageObj
loginEventListener
addLoginEventListener = function (loginEventListener) {
this.loginEventListener = loginEventListener
}
fireLoginEvent = function () {
this.loginEventListener.validateLogin(this.messageObj)
}
inputMessage = function (userName, password) {
this.messageObj = { userName, password }
this.fireLoginEvent()
}
}
/**
* 信息校验类
* 观察对象
*/
class LoginValidatorA {
validateLogin = function(event) {
if(!event.userName){
console.log('请输入名字')
}
else if(!event.password) {
console.log('请输入密码')
}
else {
console.log('输入成功', event.password, event.userName)
}
}
}
const loginBean = new LoginBean()
const loginValidator = new LoginValidatorA()
loginBean.addLoginEventListener(loginValidator)
loginBean.inputMessage('你的名字', '123456')
优化模式
图解
思路解读
- 观察者与被观察者之间增加调度中心,细化消息通知的粒度
例子分析
发布者
class Publisher {
messageObj
list = {}
// 注册回掉方法
subscribe = function (key, fun) {
if(!this.list[key]){
this.list[key] = []
}
this.list[key].push(fun)
}
// 推送消息
publish = function (key, message) {
this.list[key].forEach(funItem => funItem(message))
}
}
监听者
class Observer1 {
listen = function(message) {
console.log('第一个监听者', message)
}
}
class Observer2 {
handle = function(message) {
console.log('第二个监听者', message)
}
}
- 用此种优化可以解除监听者与被监听者之间方法名字的耦合
Main
const pub = new Publisher()
const obs1 = new Observer1()
const obs2 = new Observer2()
pub.subscribe('sing', obs1.listen)
pub.subscribe('todo', obs2.handle)
pub.publish('sing', { value: '你好世界' })
pub.publish('todo', { name: 'hello world' })
全部代码
/**
* 信息输入类
* 被观察对象
*/
class Publisher {
messageObj
list = {}
// 注册
subscribe = function (key, fun) {
if(!this.list[key]){
this.list[key] = []
}
this.list[key].push(fun)
}
// 推送消息
publish = function (key, message) {
this.list[key].forEach(funItem => funItem(message))
}
}
class Observer1 {
listen = function(message) {
console.log('第一个监听者', message)
}
}
class Observer2 {
handle = function(message) {
console.log('第二个监听者', message)
}
}
const pub = new Publisher()
const obs1 = new Observer1()
const obs2 = new Observer2()
pub.subscribe('sing', obs1.listen)
pub.subscribe('todo', obs2.handle)
pub.publish('sing', { value: '你好世界' })
pub.publish('todo', { name: 'hello world' })
模式优缺点
优点
- 解耦了表示层和数据逻辑层
- 简化一对多系统的设计
- 符合开闭原则,增加观察者无需更改被观察者代码
缺点
- 观察者增多会增加通知成本
- 观察者如果与被观察者相互依赖,则可能触发死循环
- 观察者不知道被观察者数据是如何变化的
参考资料
《设计模式--刘伟》