回调、监听器、观察者模式。这三个名词描述的都是同一件事物:
一个有状态的对象,将自身的状态发布出去,通知到那些订阅了该对象的状态的观察者(们)。
举例子:微信用户关注(或者说订阅)一个公众号,当公众号作者发布一篇推文时,所有订阅了这个公众号的用户都能收到推送。
被观察者,都是有状态的对象,将自己的某个状态发布给订阅了他的对象们。
代码举例:
class Author {
private var onPublishEssayListener: ((id: String) -> Unit)? = null
private var onUpdateEssayListener: ((id: String) -> Unit)? = null
private var onDeleteEssayListener: ((id: String) -> Unit)? = null
fun publishEssay() {
//...
//由Author自己维护何时发布回调
onPublishEssayListener?.invoke("123")
//...
}
fun deleteEssay() {
//..
//由Author自己维护何时发布回调
onDeleteEssayListener?.invoke("123")
//..
}
fun updateEssay() {
//..
//由Author自己维护何时发布回调
onUpdateEssayListener?.invoke("123")
//..
}
fun observePublish(onPublishEssayListener: (id: String) -> Unit) {
this.onPublishEssayListener = onPublishEssayListener
}
fun observeUpdate(onUpdateEssayListener: (id: String) -> Unit) {
this.onUpdateEssayListener = onUpdateEssayListener
}
fun observeDelete(onDeleteEssayListener: (id: String) -> Unit) {
this.onDeleteEssayListener = onDeleteEssayListener
}
}
fun main(args: Array<String>) {
val author = Author()
author.observePublish { id ->
log("发布文章,id=$id")
}
author.observeUpdate { id ->
log("更新文章,id=$id")
}
author.observeDelete { id ->
log("删除文章。id=$id")
}
author.publishEssay()
author.updateEssay()
author.deleteEssay()
}
打印:
发布文章,id=123
更新文章,id=123
删除文章。id=123
上述代码由Author
类直接引用了回调(用了Kotlin中的函数类型,省去了定义多个接口),在Authoer
类的内部来直接根据当前的逻辑,将注册过来的观察者给发布出去。这里可以将这些观察者(或者说回调对象)抽象出来,做成一个父类,让Author
继承。
因为观察者观察的都是文章的状态,因此这个类叫做EssayStateRegistry
abstract class EssayStateRegistry {
private var onPublishEssayListener: ((id: String) -> Unit)? = null
private var onUpdateEssayListener: ((id: String) -> Unit)? = null
private var onDeleteEssayListener: ((id: String) -> Unit)? = null
//-------------状态的通知------------------
protected fun notifyPublish(id: String) {
onPublishEssayListener?.invoke(id)
}
protected fun notifyUpdate(id: String) {
onUpdateEssayListener?.invoke(id)
}
protected fun notifyDelete(id: String) {
onDeleteEssayListener?.invoke(id)
}
//------------状态的订阅--------------------
fun observePublish(onPublishEssayListener: (id: String) -> Unit) {
this.onPublishEssayListener = onPublishEssayListener
}
fun observeUpdate(onUpdateEssayListener: (id: String) -> Unit) {
this.onUpdateEssayListener = onUpdateEssayListener
}
fun observeDelete(onDeleteEssayListener: (id: String) -> Unit) {
this.onDeleteEssayListener = onDeleteEssayListener
}
}
此时的Authoer
便干净了许多
//继承了EssayStateRegistry
class Author : EssayStateRegistry() {
fun publishEssay() {
//...
//由Author自己维护何时发布回调
notifyPublish("123")
//...
}
fun deleteEssay() {
//..
//由Author自己维护何时发布回调
notifyDelete("123")
//..
}
fun updateEssay() {
//..
//由Author自己维护何时发布回调
notifyUpdate("123")
//..
}
}
主程序代码不需要改变。
fun main(args: Array<String>) {
val author = Author()
author.observePublish { id ->
log("发布文章,id=$id")
}
author.observeUpdate { id ->
log("更新文章,id=$id")
}
author.observeDelete { id ->
log("删除文章。id=$id")
}
author.publishEssay()
author.updateEssay()
author.deleteEssay()
}
打印
发布文章,id=123
更新文章,id=123
删除文章。id=123
特点:
- 将有状态的对象
Author
与他的观察、订阅逻辑分离。他自己不再直接维护他的状态。他的状态的订阅和发布的处理细节抽象给父类。他自己只需要继承父类就可以获得转发自己状态的能力。
优点:
- 逻辑分离,简化有状态的对象
Author
的代码,让其专注主要的逻辑。 - 抽象出来的父类
EssayStateRegistry
可以拓展,其他对象只需要继承父类,就可以瞬间拥有所有父类的状态和维护状态的能力。 - 当未来可能有更多的状态需要
Author
类拓展,那么可以再抽象出一个父类XXXStateRegistry
来让Author
继承,此时Author
的代码将依然保持简洁。
缺点:
- 继承就是耦合,抽象父类的任何的改动,都将影响所有继承了父类的子类。
图: