观察者模式简介
Observer Pattern,观察者模式,也是设计模式中非常常见的一种,在此模式下,一个对象(被观察者)可以管理一大批观察者对象,并且在自己的状态发生变化时,通过接口通知观察者们,而观察者们接到通知后,可以分别作出相应的动作。
观察者与被观察者之间不会产生直接耦合,但它们是抽象耦合的(通过接口),这算是一个优点,但毕竟还是存在耦合。
观察者模式解读
从网上找来一张观察者模式的简单类图,从这张图里,我们对观察者模式中的各个角色进行解读。
- Subject(被观察者)
是一个接口(实际上也有人使用抽象类),主要包含了3个方法:
- addObserver方法可以添加观察者对象,可以理解为观察者把自己注册到了被观察者这里,只有注册了的观察者,才能接到被观察者的通知。
- deleteObserver方法是将观察者移除,被移除的观察者自然就不能再接到通知了。
- notifyObserves方法可以把通知发送给所有的已注册的观察者,至于观察者们后续做什么事情,被观察者是完全不关心的。
- Observer(观察者)
也是一个接口,必须实现的只有一个notify方法(当然在Java里你得把notify改成其他名字),被观察者通过调用这个方法,让观察者了解到事件的发生。
- ConcreteSubject(被观察者的具体实现)
在这里可以写被观察者的具体业务逻辑,另外还需要一个存储观察者的集合。一般情况下使用ArrayList就行,当然如果考虑到多线程场景,可以使用CopyOnWriteArraySet,因为线程安全嘛。
- ConcreteObserver(观察者的具体实现)
在这里写的是观察者的具体业务逻辑。毕竟一个观察者如果除了接收消息没有别的能力,那么这个观察者就没有意义了。观察者模式嘛,观察者从被观察者那里接收到了消息之后的逻辑才更加重要。
实现观察者模式的Java代码
先定义观察者接口:
// 这里的接口很简单,就只有一个update方法,被观察者通过此方法通知观察者。 public interface Observer { void update(String message); }
然后是观察者接口:
public interface Subject { // 注册观察者 void addObserver(Observer observer); // 删除观察者 void deleteObserver(Observer observer); // 通知观察者 void notifyObservers(); }
接下来就是具体的实现类了,先来一个MessageCenter,是被观察者,用来给观察者发送消息的:
public class MessageCenter implements Subject { private final CopyOnWriteArraySet<Observer> 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(); } }
然后再来一个观察者的具体实现:
public class DotaPlayer implements Observer { public String playerName; @Override public void update(String message) { 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!");
看一下运行结果:
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)划等号,认为这两者是一种设计模式。但实际上二者有一定的区别,从某种意义上说,发布订阅模式是解耦更彻底的一种特殊的观察者模式,但并不能直接判断二者孰好孰坏,还是要根据实际需求来选择。
评论