一、概念
1.1 定义
定义对象间的一种一对多的依赖关系。当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新(观察者)。
1.2 实例场景
小陈在气象局工作,可以为他的家人提供最新的天气情况。这时,小陈就是被观察者,他的家人就是观察者。他的家人订阅天气服务,小陈就可以提供最新的天气预报到订阅者手中。而他的家人收到通知后,可以做出自己的反应。
二、通用代码
2.1 目标类
这里的目标类对应着实例里的小陈,他知道观察自己的观察者(家人),并提供了注册和删除观察者的接口。
public class Subject {
private ArrayList<Observer> observers = new ArrayList<Observer>();
/**
* 添加
* @param observer 观察者
*/
public void attach(Observer observer) {
observers.add(observer);
}
/**
* 删除
* @param observer 观察者
*/
public void detach(Observer observer) {
observers.remove(observer);
}
/**
* 向所有注册的观察者发送信息
*/
protected void notifyObservers(){
for(Observer observer:observers){
observer.update(this);
}
}
}
2.2 具体目标类
这个类就相当于是天气预报的功能,负责把有关的状态存入到相应的观察者对象中。
public class ConcreatSubject extends Subject {
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
this.notifyObservers();
}
}
2.3 观察者接口
此类为观察者的接口,提供了一个更新的接口,当目标发生改变时,通知相应的观察者
public interface Observer {
/**
* 更新的接口
* @param subject subject 传入目标对象,方便获取目标的状态
*/
void update(Subject subject);
}
2.4 具体的观察者对象
这个类就相当于实例的小陈的家人,他的家人知道天气变化了之后,会采取不同的策略去改变一些事。
public class ConcreatObserver implements Observer {
//观察者状态
private String observerState;
/**
* 获取目标类的状态,同步到观察者中
*/
@Override
public void update(Subject subject) {
observerState = ((ConcreatSubject)subject).getSubjectState();
}
}
2.5 总结
这样,我们就可以通过改变ConcreatSubject里的状态值,通过循环来通知每一个注册了的观察者,让他们也做出相应的改变。
三、详细设计
3.1 天气目标类
public class WeatherSubject {
//用来保存注册的观察者对象
private ArrayList<Observer> observers = new ArrayList<Observer>();
/**
* 把订阅天气的人添加到订阅者列表中
* @param observer 观察者
*/
public void attach(Observer observer) {
observers.add(observer);
}
/**
* 删除订阅天气的人
* @param observer 观察者
*/
public void detach(Observer observer) {
observers.remove(observer);
}
/**
* 通知所有已经订阅了天气的人
*/
protected void notifyObservers(){
for(Observer observer:observers){
observer.update(this);
}
}
}
3.2 具体天气目标类
相当于天气预报,能更改天气信息,并通知他的家人(被观察者)
public class ConcreatWeatherSubject extends WeatherSubject {
private String weatherContent;
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
//天气更新,通知所有订阅天气的观察者
this.notifyObservers();
}
}
3.3 观察者类
相当于他的家人,我们细化了一些细节的信息,如名字,行为等。
public class ConcreatObserver implements Observer {
//观察者名称
private String observerName;
//天气情况
private String weatherContent;
//提醒内容
private String remindThing;
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
}
public String getRemindThing() {
return remindThing;
}
public void setRemindThing(String remindThing) {
this.remindThing = remindThing;
}
/**
* 获取目标类的状态,同步到观察者中
*/
@Override
public void update(WeatherSubject subject) {
weatherContent = ((ConcreatWeatherSubject)subject).getWeatherContent();
System.out.println(observerName+"收到了"+weatherContent+","+remindThing);
}
}
这里还可以根据天气情况,判断进行不同的事情。
3.4 测试类
对观察者模式的代码进行一个测试。
public class Client {
public static void main(String[] args) {
//1. 创建一个目标
ConcreatWeatherSubject weatherSubject = new ConcreatWeatherSubject();
//2. 创建一个观察者
ConcreatObserver observerGf = new ConcreatObserver();
observerGf.setObserverName("女票");
observerGf.setRemindThing("是我们的第一次约会,地点公园");
ConcreatObserver observerMom = new ConcreatObserver();
observerMom.setObserverName("老妈");
observerMom.setRemindThing("去逛街了");
//3. 注册观察者
weatherSubject.attach(observerGf);
weatherSubject.attach(observerMom);
//4. 目标发布天气
weatherSubject.setWeatherContent("大暴雨");
}
}
这时,我们会得到以下的输出。
女票收到了大暴雨,是我们的第一次约会,地点公园
老妈收到了大暴雨,去逛街了
3.5总结
让我们回顾一下整个流程。
首先,我们有我们的主角(目标,被观察者)小陈,和两个他的家人(观察者)。两个家人都去订阅了天气预报的服务。当天气改变时,我们的小陈会依次通知所有的订阅者,订阅者收到通知后,可以自行判断该怎么做。这就是观察者模式。