Java观察者模式
观察者模式有两个对象:
- 观察者:
Observer
- 可被观察者:
Observable
比如一个大人要照顾一个小孩子,大人需要时刻观察小孩子,以免发生意外,比如发现小孩子想要横穿马路时要及时拦住,以免被车撞,发现小孩子靠近池塘时要及时拦住, 以免落水。这个大人其实就是一个观察者,而小孩子是一个可被观察者。
当我们需要实现类似这样的功能时,完全可以自己实现观察者
和可被观察者
,但是Java提供了Observer
和Observable
,使用它们就会更简单,而且大家都用它们,则代码就会更通用。
Observer
是一个接口,它就一个update
方法,当数据发生变化时就会调用此方法,具体做什么就由我们自己去实现了。Observable
不是接口,它是一个类,提供操作观察者的方法,所以我们就不需要去实现这些操作了,直接用就行。
示例如下:
有一个消息列表和一个UI界面,当消息列表中添加了新消息时,我们希望UI界面上显示这个新消息,这里我们就简单一点直接打印这个新消息即可,示例代码如下:
import java.util.Observable
import java.util.Observerclass UI : Observer {override fun update(o: Observable, arg: Any?) {val messageList = o as MessageListprintln("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 MessageListprintln("消息列表发生了${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开始,Observer
和Observable
被标记为过时,主要原因是其设计存在一些局限性,例如事件模型不够丰富、无法序列化、以及线程安全问题等。我们可以使用比如PropertyChangeSupport
、RxJava / Reactor
、LiveData (Android)
等做为代替,其中PropertyChangeSupport
是JDK自带,无需额外依赖,PropertyChangeSupport
是 Java Beans
规范的一部分,它通过 "属性变更事件" 来工作,非常适用于基于状态的变更通知。示例如下:
import java.beans.PropertyChangeEvent
import java.beans.PropertyChangeListener
import java.beans.PropertyChangeSupportclass 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中的Observer
和Observable
的使用。