14.观察者模式(大话设计模式kotlin版)

观察者模式

定义

观察者Observer模式又叫发布-订阅Publish/Subscribe模式。它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题Subject对象。当这个主题对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。

UML图

观察者模式结构图

实现代码

Subject抽象主题类,可支持增加、移除、通知观察者对象。

/**
 * @create on 2020/6/27 23:12
 * @description 主题类 抽象通知者
 * @author mrdonkey
 */
abstract class Subject {
    private val observers = arrayListOf<Observer>()

    fun attach(observer: Observer) {
        observers.add(observer)
    }

    fun detach(observer: Observer) {
        observers.remove(observer)
    }

    fun notifyObserver() {
        observers.forEach {
            it.update()
        }
    }
}

Observer抽象观察者,定一个以update方法,当主题状态发生改变时调用。

/**
 * @create on 2020/6/27 23:14
 * @description 抽象观察者
 * @author mrdonkey
 */
abstract class Observer {
    abstract fun update()
}

ConcreteSubject 具体的主题实现类,提供Subject的所有功能,增加该主题的状态。

/**
 * @create on 2020/6/27 23:15
 * @description 具体主题
 * @author mrdonkey
 */
class ConcreteSubject : Subject() {
    var subjectState = ""
}

ConcreteObserver 具体的观察者,定义了收到主题通知时update的具体实现。

/**
 * @create on 2020/6/27 23:15
 * @description 具体观察者
 * @author mrdonkey
 */
class ConcreteObserver(var sub: ConcreteSubject, var name: String) : Observer() {
    private var observerState = ""

    override fun update() {
        observerState = sub.subjectState
        println("$name--->update:$observerState")
    }
    
}

Client 客户端测试类

/**
 * @create on 2020/6/27 23:23
 * @description 客户端类
 * @author mrdonkey
 */
class Client {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val concreteSubject = ConcreteSubject()
            concreteSubject.attach(ConcreteObserver(concreteSubject, "A"))
            concreteSubject.attach(ConcreteObserver(concreteSubject, "B"))
            concreteSubject.subjectState="HaHa"
            concreteSubject.notifyObserver()
        }
    }
}

测试结果:

A--->update:HaHa
B--->update:HaHa

分析

  • 意义
    本质上是解除耦合。让耦合的双方依赖于抽象 而不是依赖于具体,从而使得各自的变化不会影响另一边的变化。(依赖倒置原则的一种实现)
  • 使用场景
    当存在一个对象改变时需要同时改变其他对象(一个或多个)的时候。
  • 不足
    正是依赖倒置原则,使得抽象的通知者需要依赖抽象的观察者,若是没有抽象观察者这个接口,上例的通知者就无法通知观察者,再者只能指定此类型的观察者,不易拓展支持其他接口的观察者;
  • 拓展
    实际有些情况,通知者与观察者之间并不互相知道,再者通知者需通知多个不同类型的观察者,为了满足此效果,我们需要用事件委托机制来实现。

事件委托机制

定义

先有观察者模式,再有委托事件机制。委托就是一种引用方法类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托可以看作是对函数的抽象,是函数的类`,委托的实例将代表一个具体的函数。

修改代码实现简单的委托

在上例观察者模式的前提下,我们去掉抽象观察者,让抽象通知者维持一个函数列表,里面装载的是每个观察者收相应操作函数(对应抽象观察者定义的update方法,只是每个观察者并不一定都是update这个方法)
简单的说,就是从保存抽象观察者转变成保存观察者需执行函数,将定义的固定抽象接口变成一种函数类型,从而达到支持不同类型观察者的效果,进一步使程序解耦。

Subject 主题接口,提供notifyObserver方法通知观察者

/**
 * @create on 2020/6/27 23:28
 * @description 主题接口
 * @author mrdonkey
 */
interface Subject {
    fun notifyObserver()
}

ConcreteSubject 具体的主题,eventHandler保存一个观察者的key(方便删除)与观察者对应的更新方法,此例中定义的是无参无返回值的方法() -> Unit

/**
 * @create on 2020/6/27 23:29
 * @description 事件委托主题
 * @author mrdonkey
 */
class ConcreteSubject : Subject {

    private var eventHandler: HashMap<Int, () -> Unit> = hashMapOf()//保存每个观察者需要更新的方法

    override fun notifyObserver() {
        eventHandler.forEach { event ->
            event.value()//执行方法
        }
    }

    fun attach(key: Int, event: () -> Unit) {
        eventHandler[key] = event
    }

    fun detach(key: Int) {
        eventHandler.remove(key)

    }

}

ConcreteObserverA/ConcreteObserverB 具体的观察者A与B

class ConcreteObserverA {

    fun updateObserverA(){
        println("A--->updateObserverA")
    }
}

class ConcreteObserverB {

    fun updateObserverB(){
        println("B--->updateObserverB")
    }
}

Client 客户端测试

class Client {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val concreteSubject = ConcreteSubject()
            concreteSubject.attach(1) { ConcreteObserverA().updateObserverA() }
            concreteSubject.attach(2) { ConcreteObserverB().updateObserverB() }
            concreteSubject.detach(2)
            concreteSubject.notifyObserver()
        }
    }
}

输出结果:

A--->updateObserverA

分析

  • 优势
    一个委托对象可以搭载多个(支持不同类)方法,执行时所有方法将依次被唤醒。
  • 不足
    委托对象所搭载的方法必须满足相同的参数列表与返回值类型
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值