观察者Observer
模式又叫发布-订阅Publish/Subscribe
模式。它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题Subject
对象。当这个主题对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。
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
一个委托对象可以搭载多个(支持不同类)方法
,执行时所有方法将依次被唤醒。委托对象所搭载的方法必须满足相同的参数列表与返回值类型