什么是观察者模式
定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
有多个对象在关注着一个对象,如果这个对象的状态发生了改变,其它依赖(关注)它的对象就会收到通知,然后在接收到通知以后各个对象做出相应的动作。这里涉及到两个概念(观察者和被观察者(目标类)),被观察者只能有一个,而观察这个观察者的对象可以用多个。
观察者模式的结构:
Subject(被观察者或者说是目标):
attach(添加观察者)
detach(删除观察者)
notify(提醒观察者)–当被观察者的状态发生改变的时候调用这个方法
Observe(观察者):
update(更新方法)–当观察者状态发生改变调用提醒方法后观察者通过更新方法来做出不同响应(动作)。
观察者模式的实现
具体的应用步骤:
1. 创建目标(实例化目标类)
2. 创建和设置观察者(实例化观察者并且设置观察者的字段)
3. 调用目标实例的添加方法把观察者加入目标类的观察队列中
4. 改变目标类的状态
以小明和小王在气象台订阅天气预报为例,小明和小王作为观察者,气象台作为目标。
WeatherSubject.java
import java.util.ArrayList;
import java.util.List;
/**
* 目标对象类,它知道观察它的观察者,并提供添加和删除观察者的接口
*/
public class WeatherSubject {
//观察者对象
private List<WeatherObserver> observers = new ArrayList<WeatherObserver>();
//添加观察者
public void attachObserver(WeatherObserver observer){
observers.add(observer);
}
//删除观察者
public void detachObserver(WeatherObserver observer){
observers.remove(observer);
}
//通知所有观察者
protected void notifyObservers(){
for(WeatherObserver observer:observers){
observer.update(this);
}
}
}
WeatherObserver.java
/**
* 观察者接口,定义更新接口给目标发生改变时被通知的对象
*
*/
public interface WeatherObserver {
//观察者更新接口
public void update(WeatherSubject subject);
}
ConcreteWeatherSubject.java
/**
* 具体的目标对象,负责把有关状态存入到相应的观察者对象中
*
*/
public class ConcreteWeatherSubject extends WeatherSubject {
//观察者状态(天气内容)
private String subjectWeatherContent;
public String getSubjectWeatherContent() {
return subjectWeatherContent;
}
//设置目标天气内容,同时提醒所有观察者
public void setSubjectWeatherContent(String subjectWeatherContent) {
this.subjectWeatherContent = subjectWeatherContent;
this.notifyObservers();
}
}
ConcreteWeatherObserver.java
/**
* 具体的观察者对象,实现更新方法,使自身状态和目标状态保持一致
*
*/
public class ConcreteWeatherObserver implements WeatherObserver {
//观察者名字
private String observerName;
//观察者行为(天气内容)
private String observerWeatherContent;
//获取目标类的状态同步到观察者的状态中
@Override
public void update(WeatherSubject subject) {
observerWeatherContent = ((ConcreteWeatherSubject)subject).getSubjectWeatherContent();
System.out.println(observerName+"收到了天气预报:"+observerWeatherContent);
}
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
public String getObserverWeatherContent() {
return observerWeatherContent;
}
public void setObserverWeatherContent(String observerWeatherContent) {
this.observerWeatherContent = observerWeatherContent;
}
}
ObserverTest.java
public class ObserverTest {
/**
* 观察者测试类
*
*/
public static void main(String[] args) {
//创建观察者
ConcreteWeatherObserver observer1 = new ConcreteWeatherObserver();
observer1.setObserverName("小明");
ConcreteWeatherObserver observer2 = new ConcreteWeatherObserver();
observer2.setObserverName("小王");
//创建气象台目标
ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
//注册观察者
subject.attachObserver(observer1);
subject.attachObserver(observer2);
//更新目标对象
subject.setSubjectWeatherContent("晴,气温26℃,适合外出");
}
}
运行结果:
小明收到了天气预报:晴,气温26℃,适合外出
小王收到了天气预报:晴,气温26℃,适合外出
观察者的优缺点
优点:
1、观察者模式实现了观察者和目标之间的抽象耦合;
2、观察者模式实现了动态联动(一个对象的状态发生改变更新另一个对象);
3、观察者模式支持广播通信。
缺点:
可能引起无谓的操作,可能观察者不需要全部update,引起资源浪费。
观察者模式的应用场景
1、当一个抽象模型有两个方面,其中一个方面的操作依赖另一个方面的状态变化(动态联动)。
2、如果再更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变。
3、当一个对象必须通知其他的对象,但是又希望这个对象和其他被它通知的对象是松散耦合的。