观察者模式简介
Observer Pattern,观察者模式,也是设计模式中非常常见的一种,在此模式下,一个对象(被观察者)可以管理一大批观察者对象,并且在自己的状态发生变化时,通过接口通知观察者们,而观察者们接到通知后,可以分别作出相应的动作。
观察者与被观察者之间不会产生直接耦合,但它们是抽象耦合的(通过接口),这算是一个优点,但毕竟还是存在耦合。
观察者模式解读
从网上找来一张观察者模式的简单类图,从这张图里,我们对观察者模式中的各个角色进行解读。
Subject(被观察者)
是一个接口(实际上也有人使用抽象类),主要包含了3个方法:
addObserver方法可以添加观察者对象,可以理解为观察者把自己注册到了被观察者这里,只有注册了的观察者,才能接到被观察者的通知。
deleteObserver方法是将观察者移除,被移除的观察者自然就不能再接到通知了。
notifyObserves方法可以把通知发送给所有的已注册的观察者,至于观察者们后续做什么事情,被观察者是完全不关心的。
Observer(观察者)
也是一个接口,必须实现的只有一个notify方法(当然在Java里你得把notify改成其他名字),被观察者通过调用这个方法,让观察者了解到事件的发生。
ConcreteSubject(被观察者的具体实现)
在这里可以写被观察者的具体业务逻辑,另外还需要一个存储观察者的集合。一般情况下使用ArrayList就行,当然如果考虑到多线程场景,可以使用CopyOnWriteArraySet,因为线程安全嘛。
ConcreteObserver(观察者的具体实现)
在这里写的是观察者的具体业务逻辑。毕竟一个观察者如果除了接收消息没有别的能力,那么这个观察者就没有意义了。观察者模式嘛,观察者从被观察者那里接收到了消息之后的逻辑才更加重要。
实现观察者模式的Java代码
先定义观察者接口:
// 这里的接口很简单,就只有一个update方法,被观察者通过此方法通知观察者。
public interface Observer {
void update(String message);
}
1
2
3
4
// 这里的接口很简单,就只有一个update方法,被观察者通过此方法通知观察者。
publicinterfaceObserver{
voidupdate(Stringmessage);
}
然后是观察者接口:
public interface Subject {
// 注册观察者
void addObserver(Observer observer);
// 删除观察者
void deleteObserver(Observer observer);
// 通知观察者
void notifyObservers();
}
1
2
3
4
5
6
7
8
publicinterfaceSubject{
// 注册观察者
voidaddObserver(Observerobserver);
// 删除观察者
voiddeleteObserver(Observerobserver);
// 通知观察者
voidnotifyObservers();
}
接下来就是具体的实现类了,先来一个MessageCenter,是被观察者,用来给观察者发送消息的:
public class MessageCenter implements Subject {
private final CopyOnWriteArraySet observers = new CopyOnWriteArraySet<>();
private String mMessage;
@Override
public void addObserver(Observer observer) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}
@Override
public void deleteObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(mMessage);
}
}
public void sendMessage(String message) {
mMessage = message;
notifyObservers();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
publicclassMessageCenterimplementsSubject{
privatefinalCopyOnWriteArraySetobservers=newCopyOnWriteArraySet<>();
privateStringmMessage;
@Override
publicvoidaddObserver(Observerobserver){
if(!observers.contains(observer)){
observers.add(observer);
}
}
@Override
publicvoiddeleteObserver(Observerobserver){
observers.remove(observer);
}
@Override
publicvoidnotifyObservers(){
for(Observerobserver:observers){
observer.update(mMessage);
}
}
publicvoidsendMessage(Stringmessage){
mMessage=message;
notifyObservers();
}
}
然后再来一个观察者的具体实现:
public class DotaPlayer implements Observer {
public String playerName;
@Override
public void update(String message) {
System.out.println("DotaPlayer-" + playerName + "接收到信息:" + message);
}
}
1
2
3
4
5
6
7
8
publicclassDotaPlayerimplementsObserver{
publicStringplayerName;
@Override
publicvoidupdate(Stringmessage){
System.out.println("DotaPlayer-"+playerName+"接收到信息:"+message);
}
}
最后就是实际的调用了:
DotaPlayer playerA = new DotaPlayer();
playerA.playerName = "甲";
DotaPlayer playerB = new DotaPlayer();
playerB.playerName = "乙";
MessageCenter messageCenter = new MessageCenter();
messageCenter.addObserver(playerA);
messageCenter.addObserver(playerB);
messageCenter.sendMessage("圣剑代表了孤注一掷、背水一战的勇气……");
messageCenter.sendMessage("兄弟们,这波我很强,因为我有BKB!");
1
2
3
4
5
6
7
8
9
DotaPlayerplayerA=newDotaPlayer();
playerA.playerName="甲";
DotaPlayerplayerB=newDotaPlayer();
playerB.playerName="乙";
MessageCentermessageCenter=newMessageCenter();
messageCenter.addObserver(playerA);
messageCenter.addObserver(playerB);
messageCenter.sendMessage("圣剑代表了孤注一掷、背水一战的勇气……");
messageCenter.sendMessage("兄弟们,这波我很强,因为我有BKB!");
看一下运行结果:
System.out: DotaPlayer-甲接收到信息:圣剑代表了孤注一掷、背水一战的勇气……
System.out: DotaPlayer-乙接收到信息:圣剑代表了孤注一掷、背水一战的勇气……
System.out: DotaPlayer-甲接收到信息:兄弟们,这波我很强,因为我有BKB!
System.out: DotaPlayer-乙接收到信息:兄弟们,这波我很强,因为我有BKB!
在Android中的应用
观察者模式在Android里的运用十分广泛,Framework层中的观察者模式随处可见,而在很多第三方库中也有使用。
BroadcastReceiver
BroadcastReceiver就是一个十分典型的观察者模式,注册广播就是BroadcastReceiver这个观察者把自己添加到了被观察者那里(广播管理中心),然后被观察者发送某个广播时,只有注册了该广播的BroadcastReceiver才能接收到,最终在onReceive回调里收到广播再进行其他处理。
各种各样的Listener
最熟悉的当然是View. setOnClickListener这个流程了,setOnClickListener的参数OnClickListener本身就是一个接口,注册后,当发生点击事件时,View中的performClick()方法被调用,在该方法中通过mOnClickListener.onClick实现了回调。
各类Adapter
ListView、RecyclerView、ViewPager等的Adapter中,都有一个mObservable,它们归根结底都是android.database. Observable类的实现。当数据发生变化时,我们调用notifyDataSetChanged方法,最终就要依赖mObservable.notifyChanged()方法来实现数据刷新。
RxJava
这个库的强大相信很多人都有所了解。它可以很方便的实现链式调用,在主线程和其他子线程之间的切换十分便捷,在RxJava里观察者模式可以说是它的根本,才能实现如此方便的线程管理与数据流管理。代码分析就不上了,太多了,日后单独分析吧。
总结
观察者模式的优点还是比较明显的,耦合度较低,且被观察者只负责发出通知,通知都有谁接收、接收后做什么事情,一概不问。但也有可能会造成一个严重的问题,因为在notifyObservers方法里会对所有的观察者进行通知,如果观察者数量较多,甚至在update方法里执行了耗时操作,那么就有可能造成很严重的性能问题。
也有人把观察者模式与发布订阅模式(Publish-Subscribe pattern)划等号,认为这两者是一种设计模式。但实际上二者有一定的区别,从某种意义上说,发布订阅模式是解耦更彻底的一种特殊的观察者模式,但并不能直接判断二者孰好孰坏,还是要根据实际需求来选择。