观察者模式,超详细分解

395 阅读5分钟

观察者模式

观察者模式由来:

  • 在软件系统中,一个对象的状态发生变化,某些与它相关的对象也要跟着做出变化,这是一种对象和对象之间的依赖关系,一个对象发生改变时候自动通知其他对象,其他对象也做出相应的反应,通俗的说就像Vue中的computer属性。
  • 我们将发生改变的对象叫做观察目标,被通知的对象叫做观察者,一个观察目标可以对应多个观察者,观察者之间没有联系,他们可以在观察目标变化时候做出不同的反应。

生活场景

  • 就好像父母担心孩子在学校受欺负,于是想要观察自家孩子,有没有受欺负,这时候父母就是观察者,孩子是被观察者,并且父母告诉孩子,如果有人欺负你,你就通知我,我来处理,这样就避免了作为观察者的父母要一直询问孩子有没有受到欺负,当被观察者孩子受到欺负,通知了观察者父母,父母立马可以做出相应的反应,父亲可以联系老师和对方家长,母亲可以安慰孩子,并带他去医院检查,在这里观察者有两个,分别是父亲和母亲,被观察者是孩子,当被观察者发出信息,观察者都能获取,然后做出自己的反应。
  • 观察者不需要时刻盯着被观察者(例如A不需要每隔1ms就检查一次B的状态),二是采用注册(Register)或者成为订阅(Subscribe)的方式告诉被观察者:我需要你的某某状态,你要在它变化时通知我。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。
  • 总结:观察者模式,就是观察者告诉被观察者,你发生变化的时候通知我,然后被观察者发生变化的时候回通知观察者做相应变化。

应用场景

  • 一个抽象模型中,一个对象的行为依赖于另外一个对象的状态,即当目标对象的状态发生改变时,会直接影响到观察者的行为
  • 需要在系统中创建一个触发链时,A对象的行为将影响B,B对象的行为将影响C对象......,可以使用观察者模式创建一种链式触发机制。

###模式成员

  • Subject:抽象对象。抽象对象把所有观察者对象保存在一个集合里,每个对象都可以有任意数量的观察者,抽象对象提供一个接口,可以增加和删除观察者对象。
  • Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
  • ConcreteSubject:具体对象。该对象将有关状态存入具体观察者,在具体对象的内部状态发生改变时,给所有订阅过的观察者发送通知。
  • ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

上代码

//有一个学校,其中每个学生都具有发布自己成绩的功能,而且他有一个订阅列表,用来存放他需要通知的同学
//定义一个学生类,包括姓名,年级,和订阅列表

function student(name, level){
    this.name = name
    this.level = level
    this.list = []
}
//学生发布自己的成绩
student.prototype.publish = function (grade){
    console.log(this.level + '学生' + this.name + '发布了这次考试的成绩'+ grade)
    //循环订阅人列表,并且触发他们其中的回调,这样就通知到了订阅者
    this.list.forEach(function(item, index){
        item(grade)
    })
}
//学生添加订阅成绩的成员
student.prototype.subscribe = function(patriarch, fn){
    console.log(this.level+'学生'+this.name +'订阅了' +patriarch.name)
    //把自己的回调函数,添加进发布者的订阅者列表中
    patriarch.list.push(fn)
}
//这时候来了几个学生
let patriarchMing = new student('小明','二年级')

let patriarchLing = new student('小李','二年级')

let patriarchHong = new student('小红','二年级')

let patriarchBing = new student('小兵','二年级')


patriarchMing.subscribe(patriarchBing,function(grade){
    console.log('小明表示:'+ (grade > 80 ?'哇,你好厉害':'你真菜啊'))
})
patriarchLing.subscribe(patriarchBing,function(grade){
    console.log('小李表示:'+ (grade === 100 ?'哇,你好厉害':'你100分都没有啊'))
})
patriarchHong.subscribe(patriarchBing,function(){
    console.log('小红表示:继续保持呀')
})
//学生小兵发布自己的成绩
patriarchBing.publish(90)


小结:整体流程就是先创建一个被观察者对象,他有自己的信息,和一个订阅者列表,里面放了订阅他信息的人的回调,还有一个发布信息的函数,每次发布之后会循环观察者列表,触发他们的回调,然后观察者们就都得到消息,做出自己反应 777

优缺点

  • 优点

    • 省去了反复检索状态的资源消耗。
    • 得到更快的响应速度。
  • 缺点:

    • 如果一个被观察者对象有很多直接或者间接的观察者的话,将所有观察者都通知会发挥很多时间。
    • 如果观察者和观察目标之间有循环依赖的话,观察目标会触发他们之间的循环调用,可能导致系统崩溃。
    • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而是仅仅只知道目标发生了变化。