观察者模式是一个很重要的设计模式。
那么什么是观察者模式呢?
《Head First》中的定义: 观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
在观察者模式中,主要有两个角色,一个是主题对象(Subject/Observable),另一个是观察者对象(Observer)。在模式中有一个主题对象,有多个观察者对象。观察者对象依赖于主题对象。
如上图所示,四个observer依赖于Subject,当Subject的状态发生改变,将会自动通知observer。这里提供一种观察者模式的实现方式:
Subject只知道观察者实现了某个接口Observer,主题不需要知道观察者的具体类是什么,实现细节是什么。主题唯一依赖的就是实现Observer接口的对象列表,所以我们可以在运行时增加,删除,更换观察者。主题不受任何影响。这样建立了交互对象的松耦合设计。
我们设想一个场景:你是一次自由行的组织者(Organizer),你需要统计此次自由行的人数(travelerNum),前往地点(terminal)及其相关信息(information),然后你获取了信息,你要实时通知成行的其他成员(Traveler),联系车辆(Driver)。在这里,我们的Organizer就是Subject,我们的Traveler和Driver就是Observer。需要传递的消息有travelerNum,terminal和information。
Subject接口:
public interface Observable {
//注册
public void registerObserver(Observer o);
//删除
public void removeObserver(Observer o);
//通知
public void notifyObservers();
}
Observer接口:
public interface Observer {
//更新相关信息
public void update(int travelerNum,String terminal,String information);
}
我们再添加一个,进行操作的接口TravelPrepare()
public interface TravelPrepare {
void doPrepare();
}
Organizer类去实现Subject也就是Observable接口
public class Organizer implements Observable {
//用于存放observer的List
private ArrayList observers;
//旅客人数
private int travelerNum;
//目的地
private String terminal;
//相关信息
private String information;
//构造器,要先new observers否则会空指针
public Organizer(){
observers = new ArrayList();
}
//有新的观察者加入,例如:加入了新的同行者
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
//删除观察者,例如:有同行者退出
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0){
observers.remove(i);
}
}
//通知观察者信息发生改变了
@Override
public void notifyObservers() {
for (int i = 0;i < observers.size();i++){
Observer observer = (Observer) observers.get(i);
observer.update(travelerNum,terminal,information);
}
}
//更新旅行信息
public void setTravelInformation(int travelerNum,String terminal,String information){
this.travelerNum = travelerNum;
this.information = information;
this.terminal = terminal;
notifyObservers();
}
}
一个Driver类和一个Traveler类去实现Observer接口
public class Traveler implements Observer,TravelPrepare {
//旅客人数
private int travelerNum;
//目的地
private String terminal;
//相关信息
private String information;
//主题
private Observable organizer;
public Traveler(Observable organizer) {
this.organizer = organizer;
organizer.registerObserver(this);
}
@Override
public void update(int travelerNum, String terminal, String information) {
this.travelerNum = travelerNum;
this.terminal = terminal;
this.information = information;
doPrepare();
}
@Override
public void doPrepare() {
System.out.println("我已知悉这次旅行有"+travelerNum+"人,前往"+terminal+",其他相关信息有"+information);
}
}
public class Driver implements Observer,TravelPrepare {
//旅客人数
private int travelerNum;
//目的地
private String terminal;
//相关信息
private String information;
//主题
private Observable organizer;
public Driver(Observable organizer) {
this.organizer = organizer;
organizer.registerObserver(this);
}
@Override
public void update(int travelerNum, String terminal, String information) {
this.travelerNum = travelerNum;
this.terminal = terminal;
this.information = information;
doPrepare();
}
@Override
public void doPrepare() {
System.out.println("我将准备"+travelerNum+"座位的车辆,将前往"+terminal);
}
}
最后模拟测试
public class TravelSimulator {
public static void main(String[] args) {
Organizer organizer = new Organizer();
Traveler traveler = new Traveler(organizer);
Driver driver = new Driver(organizer);
organizer.setTravelInformation(10,"九华山","安徽");
organizer.setTravelInformation(30,"峨眉山","四川");
}
}
结果
观察者模式的优点:
1.因为它是松耦合的所以极易扩展。
2.建立了一套触发机制,可以看到是链式的触发方式,但是如果对象太多,这又会给性能造成很大的负担。
应用场景:
1、一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
2、一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
3、一个对象必须通知其他对象,而并不知道这些对象是谁。
4、需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。