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

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

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

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

    代码举例:

    1. class Author {
    2. private var onPublishEssayListener: ((id: String) -> Unit)? = null
    3. private var onUpdateEssayListener: ((id: String) -> Unit)? = null
    4. private var onDeleteEssayListener: ((id: String) -> Unit)? = null
    5. fun publishEssay() {
    6. //...
    7. //由Author自己维护何时发布回调
    8. onPublishEssayListener?.invoke("123")
    9. //...
    10. }
    11. fun deleteEssay() {
    12. //..
    13. //由Author自己维护何时发布回调
    14. onDeleteEssayListener?.invoke("123")
    15. //..
    16. }
    17. fun updateEssay() {
    18. //..
    19. //由Author自己维护何时发布回调
    20. onUpdateEssayListener?.invoke("123")
    21. //..
    22. }
    23. fun observePublish(onPublishEssayListener: (id: String) -> Unit) {
    24. this.onPublishEssayListener = onPublishEssayListener
    25. }
    26. fun observeUpdate(onUpdateEssayListener: (id: String) -> Unit) {
    27. this.onUpdateEssayListener = onUpdateEssayListener
    28. }
    29. fun observeDelete(onDeleteEssayListener: (id: String) -> Unit) {
    30. this.onDeleteEssayListener = onDeleteEssayListener
    31. }
    32. }
    33. fun main(args: Array<String>) {
    34. val author = Author()
    35. author.observePublish { id ->
    36. log("发布文章,id=$id")
    37. }
    38. author.observeUpdate { id ->
    39. log("更新文章,id=$id")
    40. }
    41. author.observeDelete { id ->
    42. log("删除文章。id=$id")
    43. }
    44. author.publishEssay()
    45. author.updateEssay()
    46. author.deleteEssay()
    47. }

    打印:

    1. 发布文章,id=123
    2. 更新文章,id=123
    3. 删除文章。id=123

    上述代码由Author类直接引用了回调(用了Kotlin中的函数类型,省去了定义多个接口),在Authoer类的内部来直接根据当前的逻辑,将注册过来的观察者给发布出去。这里可以将这些观察者(或者说回调对象)抽象出来,做成一个父类,让Author继承。

    因为观察者观察的都是文章的状态,因此这个类叫做EssayStateRegistry

    1. abstract class EssayStateRegistry {
    2. private var onPublishEssayListener: ((id: String) -> Unit)? = null
    3. private var onUpdateEssayListener: ((id: String) -> Unit)? = null
    4. private var onDeleteEssayListener: ((id: String) -> Unit)? = null
    5. //-------------状态的通知------------------
    6. protected fun notifyPublish(id: String) {
    7. onPublishEssayListener?.invoke(id)
    8. }
    9. protected fun notifyUpdate(id: String) {
    10. onUpdateEssayListener?.invoke(id)
    11. }
    12. protected fun notifyDelete(id: String) {
    13. onDeleteEssayListener?.invoke(id)
    14. }
    15. //------------状态的订阅--------------------
    16. fun observePublish(onPublishEssayListener: (id: String) -> Unit) {
    17. this.onPublishEssayListener = onPublishEssayListener
    18. }
    19. fun observeUpdate(onUpdateEssayListener: (id: String) -> Unit) {
    20. this.onUpdateEssayListener = onUpdateEssayListener
    21. }
    22. fun observeDelete(onDeleteEssayListener: (id: String) -> Unit) {
    23. this.onDeleteEssayListener = onDeleteEssayListener
    24. }
    25. }

    此时的Authoer便干净了许多

    1. //继承了EssayStateRegistry
    2. class Author : EssayStateRegistry() {
    3. fun publishEssay() {
    4. //...
    5. //由Author自己维护何时发布回调
    6. notifyPublish("123")
    7. //...
    8. }
    9. fun deleteEssay() {
    10. //..
    11. //由Author自己维护何时发布回调
    12. notifyDelete("123")
    13. //..
    14. }
    15. fun updateEssay() {
    16. //..
    17. //由Author自己维护何时发布回调
    18. notifyUpdate("123")
    19. //..
    20. }
    21. }

    主程序代码不需要改变。

    1. fun main(args: Array<String>) {
    2. val author = Author()
    3. author.observePublish { id ->
    4. log("发布文章,id=$id")
    5. }
    6. author.observeUpdate { id ->
    7. log("更新文章,id=$id")
    8. }
    9. author.observeDelete { id ->
    10. log("删除文章。id=$id")
    11. }
    12. author.publishEssay()
    13. author.updateEssay()
    14. author.deleteEssay()
    15. }

    打印

    1. 发布文章,id=123
    2. 更新文章,id=123
    3. 删除文章。id=123

    特点:

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

    优点:

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

    缺点:

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

    图:

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