观察者模式是一种一对多的关系,当目标对象状态发生改变时,它会通知观察者。
1、定义
定义对象间一种一对多的关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并更新自己。
2、使用场景
- 当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化。
- 改变一个对象的时候,需要同时连带改变其他对象,并且不知道有多少对象需要连带改变。
- 当一个对象需要通知其他对象,但是又洗完这个对象和被通知的对象时松耦合的。
3、UML图
4、示例代码
/**
* 观察者接口
*/
public interface Observer {
public void update(Subject subject);
}
public class ConcreteObservers implements Observer {
@Override
public void update(Subject subject) {
String state = ((ConcreteSubject) subject).getSubjectState();
System.out.println("被观察者状态:" + state);
}
}
public class Subject {
private List<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);
}
/**
* 通知所有观察者对象
*/
public void notifyObservers() {
for(Observer o : observers) {
o.update(this);
}
}
}
public class ConcreteSubject extends Subject {
//示意,目标对象状态
private String subjectstate;
public String getSubjectState() {
return subjectstate;
}
public void setSubjectState(String state) {
this.subjectstate = state;
this.notifyObservers();
}
}
5、推模型和拉模型
- 推模型:目标对象主动向观察者推送目标对象的详细信息。推送的通常是目标对象的全部或部分数据。
public interface Observer {
//如果把状态信息直接传给观察者,就是推模型了
public void update(String subjectState);
}
- 拉模型:目标对象通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到目标对象中获取。
public interface Observer {
//具体改变的信息需要观察者自己从 subject 对象中获取
public void update(Subject subject);
}
6、Java中的观察者模式
大家都知道 Java 中已经有观察者模式的部分实现了。就是实现 Observable 和 Observer 接口。示例如下:
被观察者
import java.util.Observable;
public class ConcreteSubject extends Observable {
//示意,目标对象状态
private String subjectstate;
public void setSubjectState(String state) {
this.subjectstate = state;
//标识状态或内容发生改变
setChanged();
this.notifyObservers(state);
}
}
观察者
import java.util.Observable;
import java.util.Observer;
public class ConcreteObservers implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("被观察者状态:" + arg);
}
}
需要注意的地方:
- 具体目标对象里面不需要再维护观察者的注册信息了,Observable 类已经帮忙实现好了。
- 触发通知时,要先调用 setChanged() 方法,这是为了帮助实现更精细地触发控制而提供的功能。
- update 方法能同时支持推模型和拉模型。