定义
- 观察者
Observer
,也称订阅者Subscriber
- 被观察者
Observable
,也称主题Subject
定义对象间(被观察者和观察者)一种一对多的依赖关系,使得每当一个对象(被观察者)改变状态时,则所有依赖于它的对象(观察者)都能得到通知并被自动更新。类似于发布/订阅模式,Observer
订阅主题,Observable
则负责发布内容,从而将二者联系起来。
使用场景
- 用于解决解耦问题,观察者和被观察者高度分离,只依赖于
Observer
和Observable
抽象; - 关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系;
- 事件多级触发场景;
- 跨系统消息交换场景,如消息队列,事件总线的处理机制。
Andorid源码实例
-
ListView
适配器Adapter
的notifyDataSetChanged()
方法,在方法中遍历所有的观察者,回调其onChanger()
方法; -
BroadcastReceiver
的注册与触发,通过Context.registerReceiver()
方法将BroadcastReceiver
(相当于观察者)注册到AMS中,当通过sendBroadcast()
发送广播时(相当于主题数据发生变更),所有注册了对应IntentFilter action
的BroadcastReceiver
将会被执行; -
EventBus
消息总线 -
java.util
包中也有Observable
和Observer
的默认实现,可参考使用
UML类图
代码示例
首先定义抽象观察者,观察者只关心主题的变更
public interface Observer {
/**
* 处理数据更新的方法(在主题发生变更时由主题主动触发)
*
* @param message 变更的数据部分
*/
void update(String message);
}
接着定义抽象主题(作为被观察者,也有命名为Observable
),主题是供观察者观察的对象
public interface Subject {
/**
* 订阅操作
* @param observer 观察者
*/
void registerObserver(Observer observer);
/**
* 取消订阅操作
* @param observer 观察者
*/
void removeObserver(Observer observer);
/**
* 通知变动
*/
void notifyChanged();
}
接着实现观察者,对主题变更作具体处理
public class Subscriber implements Observer {
private String name;
private String message;
public Subscriber(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
private void read() {
System.out.println(name + " 收到新消息: " + message);
}
}
最后再实现主题
public class Publisher implements Subject {
private String message;
private List<Observer> observerList = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyChanged() {
for (Observer observer : observerList) {
observer.update(message);
}
}
public void pushMessage(String message) {
this.message = message;
System.out.println("出版社发布新消息: " + message);
// 推送消息
notifyChanged();
}
}
作如下测试:
public class Test {
public static void main(String[] args) {
Subscriber john = new Subscriber("John");
Subscriber jack = new Subscriber("jack");
Subscriber tom = new Subscriber("tom");
Publisher publisher = new Publisher();
publisher.registerObserver(john);
publisher.registerObserver(jack);
publisher.registerObserver(tom);
publisher.pushMessage("Today is Monday");
publisher.removeObserver(jack);
publisher.pushMessage("Today is Tuesday");
}
}
输出结果如下:
出版社发布新消息: Today is Monday
John 收到新消息: Today is Monday
jack 收到新消息: Today is Monday
tom 收到新消息: Today is Monday
出版社发布新消息: Today is Tuesday
John 收到新消息: Today is Tuesday
tom 收到新消息: Today is Tuesday
优点
- 观察者和被观察者之间是抽象耦合,可灵活应对业务变化;
- 增强系统灵活性,可扩展性。
缺点
- 运用时需要考虑开发效率和运行效率问题,程序中包括一个被观察者、多个观察者、开发和调试等内容会比较复杂;
- 在Java中消息的通知默认是顺序执行,一个观察者卡顿,会影响其他观察者的执行,所以通常情况下会采用异步的方式实现update()方法