观察者模式:将对象的状态监听器抽象

字数 565阅读 31

回调、监听器、观察者模式。这三个名词描述的都是同一件事物:

一个有状态的对象,将自身的状态发布出去,通知到那些订阅了该对象的状态的观察者(们)。

举例子:微信用户关注(或者说订阅)一个公众号,当公众号作者发布一篇推文时,所有订阅了这个公众号的用户都能收到推送。

被观察者,都是有状态的对象,将自己的某个状态发布给订阅了他的对象们。

代码举例:

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

特点:

  1. 将有状态的对象Author与他的观察、订阅逻辑分离。他自己不再直接维护他的状态。他的状态的订阅和发布的处理细节抽象给父类。他自己只需要继承父类就可以获得转发自己状态的能力。

优点:

  1. 逻辑分离,简化有状态的对象Author的代码,让其专注主要的逻辑。
  2. 抽象出来的父类EssayStateRegistry可以拓展,其他对象只需要继承父类,就可以瞬间拥有所有父类的状态和维护状态的能力。
  3. 当未来可能有更多的状态需要Author类拓展,那么可以再抽象出一个父类XXXStateRegistry来让Author继承,此时Author的代码将依然保持简洁。

缺点:

  1. 继承就是耦合,抽象父类的任何的改动,都将影响所有继承了父类的子类。

图:

推荐阅读更多精彩内容