观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。
定义
关于定义,最准确的莫过于Head First设计模式中写到的。
观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象。这样一来,当被观察者状态发生改变时,需要通知相应的观察者,使这些观察者对象能够自动更新。
关键要素
(抽象)主题 Subject
主题,也就是被观察者(Observable),是观察者观察的对象,一个主题必须具备下面三个特征。
- 持有监听的观察者的引用
- 支持增加和删除观察者
- 主题状态改变,通知观察者
具体主题 ConcreteSubject
该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发出通知,具体主题角色又叫做具体观察者(Concrete Observable)
(抽象)观察者 Observer
当主题发生变化,收到通知,进行具体的处理。
具体观察者 ConcreteObserver
该角色实现抽象观察者角色所定义的更新接口,以备在主题的状态发生变化时更新自身的状态。
为什么要用这种模式
这里举一个例子来说明,牛奶送奶站就是主题,订奶客户为监听者,客户从送奶站订阅牛奶后,会每天收到牛奶。如果客户不想订阅了,可以取消,以后就不会收到牛奶。
松耦合
- 观察者增加或删除无需修改主题的代码,只需调用主题对应的增加或者删除的方法即可。
- 主题只负责通知观察者,但无需了解观察者如何处理通知。举个例子,送奶站只负责送递牛奶,不关心客户是喝掉还是洗脸。
- 观察者只需等待主题通知,无需观察主题相关的细节。还是那个例子,客户只需关心送奶站送到牛奶,不关心牛奶由哪个快递人员,使用何种交通工具送达。
通知不错过
由于被动接受,正常情况下不会错过主题的改变通知。而主动获取的话,由于时机选取问题,可能导致错过某些状态。
Java实现
public class ObserverMain {
//好处:松耦合(被观察者可以增加删除观察者;被观察者只负责通知观察者;观察者只需等待通知;)
// 通知不错过(被动接受,不易错过通知)
public static void main(String[] args) {
MilkProvider provider = new MilkProvider();
Consumer consumer1 = new Consumer("道格拉斯");
Consumer consumer2 = new Consumer("图灵");
Consumer consumer3 = new Consumer("牛顿");
provider.addObserver(consumer1);
provider.addObserver(consumer2);
provider.addObserver(consumer3);
provider.deleteObserver(consumer3);
provider.milkProduced("草莓味的牛奶");
}
// 静态成员属于类,不需要生成对象就存在了.
// 而非静态需要生成对象才产生,所以静态成员不能直接访问.所以声明为静态类
// 被观察者 牛奶站
static class MilkProvider extends Observable {
// 牛奶做好啦
public void milkProduced(String milkType) {
// 标识状态或内容发生改变
setChanged();
// 通知所有订奶的客户(观察者)
notifyObservers(milkType);
}
}
//观察者 订奶的客户
static class Consumer implements Observer {
private String name;
public Consumer(String name) {
this.name = name;
}
@Override
public void update(Observable observable, Object o) {
System.out.println("Hi, " + name + " 牛奶做好啦!" + " observable=" + observable + " o=" + o);
}
@Override
public String toString() {
return "toString " + name;
}
}
}
参考资料: