Java观察者模式

发布于:2025-09-10 ⋅ 阅读:(23) ⋅ 点赞:(0)

观察者模式有两个对象:

  1. 观察者:Observer
  2. 可被观察者:Observable

比如一个大人要照顾一个小孩子,大人需要时刻观察小孩子,以免发生意外,比如发现小孩子想要横穿马路时要及时拦住,以免被车撞,发现小孩子靠近池塘时要及时拦住, 以免落水。这个大人其实就是一个观察者,而小孩子是一个可被观察者。

当我们需要实现类似这样的功能时,完全可以自己实现观察者可被观察者,但是Java提供了ObserverObservable,使用它们就会更简单,而且大家都用它们,则代码就会更通用。

  • Observer 是一个接口,它就一个update方法,当数据发生变化时就会调用此方法,具体做什么就由我们自己去实现了。
  • Observable不是接口,它是一个类,提供操作观察者的方法,所以我们就不需要去实现这些操作了,直接用就行。

示例如下:

有一个消息列表和一个UI界面,当消息列表中添加了新消息时,我们希望UI界面上显示这个新消息,这里我们就简单一点直接打印这个新消息即可,示例代码如下:

import java.util.Observable
import java.util.Observer

class UI : Observer {
    override fun update(o: Observable, arg: Any?) {
        val messageList = o as MessageList
        println("New message: ${messageList.messages.last()}")
    }
}

class MessageList : Observable() {
    val messages = mutableListOf<String>()
    fun add(message: String) {
        messages.add(message)
        setChanged()
        notifyObservers()
    }
}

fun main() {
    val messageList = MessageList()
    val ui = UI()
    messageList.addObserver(ui)
    messageList.add("Hello")
    
    // 当不再需要观察时
    messageList.deleteObserver(ui)
}

如上代码,当我们往messageList中添加一个消息时,UI就会得到通知,具体就是UI的update方法被调用。

Observable类的功能非常简单的,看一下它的源代码实现即可了解其原理。

通知观察者时,还可以带一个参数,比如我们对消息列表有增、删、改、查的操作,我们想让观察者知道我们是一个什么样的操作,就可以在通知的时候添加参数,比如通知添加了一个消息:

class UI : Observer {
    override fun update(o: Observable, arg: Any?) {
        val messageList = o as MessageList
        println("消息列表发生了${arg}操作:${messageList.messages.last()}")
    }
}

class MessageList : Observable() {
    val messages = mutableListOf<String>()
    fun add(message: String) {
        messages.add(message)
        setChanged()
        notifyObservers("add")
    }
}

fun main() {
    val messageList = MessageList()
    val ui = UI()
    messageList.addObserver(ui)
    messageList.add("Hello")
}

运行结果为:

消息列表发生了add操作:Hello

自Java 9开始,ObserverObservable被标记为过时,主要原因是其设计存在一些局限性,例如事件模型不够丰富、无法序列化、以及线程安全问题等。我们可以使用比如PropertyChangeSupportRxJava / ReactorLiveData (Android)​等做为代替,其中PropertyChangeSupport是JDK自带,无需额外依赖,PropertyChangeSupportJava Beans 规范的一部分,它通过 ​​"属性变更事件"​​ 来工作,非常适用于基于状态的变更通知。示例如下:

import java.beans.PropertyChangeEvent
import java.beans.PropertyChangeListener
import java.beans.PropertyChangeSupport

class MessageList {
    // 持有 PropertyChangeSupport 实例
    private val pcs = PropertyChangeSupport(this)
    val messages = mutableListOf<String>()

    // 添加观察者
    fun addPropertyChangeListener(listener: PropertyChangeListener) {
        pcs.addPropertyChangeListener(listener)
    }

    // 移除观察者
    fun removePropertyChangeListener(listener: PropertyChangeListener) {
        pcs.removePropertyChangeListener(listener)
    }

    fun add(message: String) {
        val oldValue = messages.size // 可以传递旧值,这里简单用大小示意
        messages.add(message)
        // 触发通知,传递属性名、旧值和新值
        pcs.firePropertyChange("messages", oldValue, messages.size)
        // 也可以触发一个更泛化的事件,比如只通知“列表变了”
        // pcs.firePropertyChange("messageAdded", null, message)
    }
}

class UI : PropertyChangeListener {
    override fun propertyChange(evt: PropertyChangeEvent) {
        // 根据属性名判断发生了什么变化
        when (evt.propertyName) {
            "messages" -> println("消息列表发生了变化:新增了消息,当前总数 ${evt.newValue}")
            // 可以处理其他属性...
        }
        // 如果 fire 的是具体消息
        // println("消息列表新增了:${evt.newValue}")
    }
}

fun main() {
    val messageList = MessageList()
    val ui = UI()
    messageList.addPropertyChangeListener(ui)
    messageList.add("Hello")
}

当我们想学习RxJava的时候,最好先学习一下Java中的ObserverObservable的使用。


网站公告

今日签到

点亮在社区的每一天
去签到