【设计模式】观察者模式

in 设计模式 with 0 comment

简介

观察者模式(Observer Pattern),也被称为发布-订阅模式(Publish/Subscribe)模式,隶属于行为模式的其中一种。其定义了对象之间的一对多的依赖关系,当一个对象的状态发生改变的时候,所有依赖于它的对象都能得到通知并且自动更新。当对象间存在一种一对多的关系依赖关系时,则可以使用观察者模式。

要点

  1. 其定义了对象之间的一对多关系
  2. 当被观察着的状态发生变化时,所有的观察者都能得到通知。(无论是被观察者推消息还是观察者拉消息)
  3. 观察者得到通知后,能自动更新自身

结构

05

Observer : 观察者的抽象接口

Subject : 被观察者的抽象接口

ConcreteObserver : 观察者抽象接口的具体实现

ConcreteSubject : 被观察者抽象接口的具体实现

首先根据目的我们可以知道最终的效果是能够让被观察者能够在观察者发生状态变化的时候能自动更新。所以,被观察者Observer中就需要有一个方法来更新自己,在上图中对应Observernotify()

那么被观察者的义务就是在自己状态更新的时候通知所有的观察者。由图中我们可以看到,其中的被观察者中包含了一个观察者的数据集合(ObserverCollection),这同时也是核心所在,当被观察者状态发生变化的时候,就可以通过ObserverCollection来进行遍历得到所有的观察者的引用,调用他们的notify()方法来通知所有的观察者更新。被观察者下面的notifyObservers()正是起到这样一个作用。剩余的addObserver()deleteObserver()顾名思义则是用来进行观察和取消观察的。

例子

举一个在Android开发中也常见的例子。比如说Android的那些Listener,比方说一个View里面的多个OnClickListener其中的addListener()removeListener()就好比上面结构图中的addObserver()deleteObserver(),而View对象也以集合形式持有这些Listener的引用。一旦当点击事件发生到这个View上的时候,则会遍历所有的Listener来执行其onClick()方法通知时间,对应上图中的notify()

Kotlin程序例子如下:

// 观察者抽象接口
interface Observer{
    fun onEvent()
}
// 被观察者抽象接口
abstract class Subject{
    abstract val observerList : Collection<Observer>

    abstract fun notifyObserver()
    abstract fun addObserver(observer:Observer)
    abstract fun removeObserver(observer:Observer)
}
// 观察者具体实现
class ConcreteObserver(val name:String, var subject:ConcreteSubject) : Observer{

    override fun onEvent() {
        println("$name : 收到通知,subject变更为${subject.mState}")
    }

}
// 被观察者具体实现
class ConcreteSubject : Subject(){
    override val observerList = ArrayList<Observer>()

    override fun notifyObserver() {
        observerList.forEach { it.onEvent() }
    }

    override fun addObserver(observer: Observer) {
        observerList.add(observer)
    }

    override fun removeObserver(observer: Observer) {
        observerList.remove(observer)
    }

    var state = 0
        set(value) {
            field = value
            notifyObserver()
        }

}
fun main(args: Array<String>) {
    // 创建被观察者
    val subject = ConcreteSubject()
    // 创建观察者
    val observerJake = ConcreteObserver("Jake", subject)
    val observerLyon = ConcreteObserver("Lyon", subject)
    val observerLinkzr = ConcreteObserver("Linkzr", subject)
    // 观察者观察被观察者
    subject.addObserver(observerJake)
    subject.addObserver(observerLyon)
    subject.addObserver(observerLinkzr)
    // 被观察者发生改变
    println("== 变更为200 ==")
    subject.state = 200
    // 移除一个被观察者
    subject.removeObserver(observerLyon)
    // 被观察者发生改变
    println("== 变更为404 ==")
    subject.state = 404
}

执行上面的程序,打印的日志如下

== 变更为200 ==
Jake : 收到通知,subject变更为200
Lyon : 收到通知,subject变更为200
Linkzr : 收到通知,subject变更为200
== 变更为404 ==
Jake : 收到通知,subject变更为404
Linkzr : 收到通知,subject变更为404

Process finished with exit code 0

由此可以看到,当被观察者的state发生变化时,被观察者也都能得到相应的通知更新

这里通知我是采用了观察者在更新时拉信息,那也可以在被观察者发生状态变化时把信息以参数的形式推到观察者哪里去。像这样子fun onEvent(state:Int)

注意

  1. 要防止观察者于被观察者之间相互关联导致双方一直相互通知更新引起的问题。(有点类似广播风暴)
  2. 小心在通知观察者更新的时候,其中一个观察者发生异常导致在这后的观察者都得不到通知

参考资料

观察者模式 - 菜鸟教程

观察者模式 - 维基百科,自由的百科全书