一 简介
观察者模式
说白了,就是一个对发生改变,所有依赖于它的对象也发生改变,这是一对多的关系。
比如对象A,对象B,对象C。B与C依赖于A,那么A发生改变,B与C也将发生改变。此时A是被观察者,B与C是观察者。
观察者模式又被称作发布/订阅模式,主要是为了让观察者与被观察者之间进行解耦。
二 UML图
角色说明:
- Subject(抽象主题):被观察者的一个抽象类,它会把所有观察者的引用保存在一个集合里。抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject(具体主题):具体的被观察者。当具体被观察者的状态发生改变的时候,会给每一个注册过的观察者发送通知。
- Observer(抽象观察者):所有具体观察者的一个抽象类,为所有的具体观察者定义了一个接口:得到主题的通知时候更新自己。
- ConcrereObserver(具体观察者):抽象观察者的具体实现。
三 代码实例
3.1 背景
上课铃声响起时候,老师与学生们的不同反应。
3.2 定义一个抽象主题
该抽象主题定义了一些通用的方法,即具体主题里面需要实现的。
//抽象被观察者
interface Observable {
fun addObserver(observer:Observer)
fun deleteObserver(observer:Observer)
fun notifyObserver(msg:String)
}
3.2、创建一个具体主题(上课铃声)
class AlarmClock : Observable {
var list = ArrayList<Observer>()
override fun addObserver(observer: Observer) {
list.add(observer)
}
override fun deleteObserver(observer: Observer) {
list.remove(observer)
}
override fun notifyObserver(msg: String) {
for(observer in list){
observer.runaction(msg)
}
}
}
3.3、创建抽象观察者
定义了所有具体观察者需要实现的方法,听到铃声后的行为//抽象观察者
interface Observer {
var name:String
fun runaction(msg:String)
}
3.4 创建具体观察者
class Students(override var name: String) : Observer {
override fun runaction(msg: String) {
System.out.println(msg + name + "开始听课");
Log.d("jack",msg + name + "开始听课")
}
class Teachers(override var name: String) : Observer {
override fun runaction(msg: String) {
Log.d("jack",msg +name+ "老师开始讲课")
}
}
3.5 实现
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val alarmClock: Observable = AlarmClock()
val student1: Observer = Students("小屁孩")
val student2: Observer = Students("大屁孩")
val teacher: Observer = Teachers("十佳教师")
//注册观察者
//注册观察者
alarmClock.addObserver(student1)
alarmClock.addObserver(student2)
alarmClock.addObserver(teacher)
//被观察者通知已经注册的观察者
//被观察者通知已经注册的观察者
alarmClock.notifyObserver("上课铃声已经响了")
}
3.6 结果
D/jack: 上课铃声已经响了小屁孩开始听课
D/jack: 上课铃声已经响了大屁孩开始听课
D/jack: 上课铃声已经响了十佳教师老师开始讲课
四 应用场景
- 当一个对象的改变需要通知其它对象改变时,而且它不知道具体有多少个对象有待改变时。
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁
- 跨系统的消息交换场景,如消息队列、事件总线的处理机制。
优点
- 解除观察者与主题之间的耦合。让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
- 易于扩展,对同一主题新增观察者时无需修改原有代码。
缺点
-
依赖关系并未完全解除,抽象主题仍然依赖抽象观察者。
-
使用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
-
可能会引起多余的数据通知。
五 android源码应用
-
点击事件
-
listView的刷新
-
广播等等