观察者模式是指一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。比如说软件开发时的热更新功能,修改了代码之后能够自动重新部署。
原理

(idea自动生成的类图)
Subject:被观察对象的抽象类,持有一个List保存观察者对象的引用,可以添加、删除观察者对象,并且在发生变化时通知所有的观察者。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public abstract class Subject {
private List<Observer> observerList = new ArrayList<Observer>();
public void addObserver(Observer o){
observerList.add(o);
}
public void deleteObserver(Observer o){
observerList.remove(o);
}
public void notifyObservers(){
for(Observer o : observerList){
//把自身的引用传给观察者
o.update(this);
}
}
}
Observer: 观察者的接口,有一个update()方法来给被观察者调用,接受Subject的更新通知1
2
3public interface Observer {
void update(Subject subject);
}
ConcretSubject: Subject的具体类,代表具体的被观察对象的类,状态发生改变时需要调用notifyObservers()方法通知观察者1
2
3
4
5
6
7
8
9
10
11
12
13public class ConcreteSubject extends Subject{
private String state;
public String getState() {
return state;
}
public void change(String newState){
state = newState;
System.out.println("被观察对象的状态为:" + state);
this.notifyObservers();
}
}
ConcretObserver: Observer的具体类,接受目标对象(被观察者)的更新通知,并作出反应。1
2
3
4
5
6
7
8
9public class ConcreteObserver implements Observer {
private Subject subject;
//接收目标对象的引用
public void update(Subject subject) {
this.subject = subject;
System.out.println("观察者观察到状态改变,状态为: " + ((ConcreteSubject)subject).getState());
}
}
我们测试一下:1
2
3
4
5
6
7
8
9
10public class Test {
public static void main(String[] args){
ConcreteSubject subject = new ConcreteSubject();
Observer observer = new ConcreteObserver();
subject.addObserver(observer);
subject.change("hello,this is my new state");
}
}
结果:1
2被观察对象的状态为:hello,this is my new state
观察者观察到状态改变,状态为: hello,this is my new state
Jdk中的工具
jdk已经为我们提供了目标对象的抽象类和观察者的接口,分别为java.util.Observable,java.util.Observer。我们只要继承/实现抽象类与接口就行了。下面看一个使用的例子:
假设一个场景:花匠养花。当花干枯的时候花匠需要浇水,当花盛开的时候花匠觉得开心。
花是被观察的,也就是目标对象,继承Observable1
2
3
4
5
6
7
8
9
10
11
12
13public class Bloom extends Observable {
public void dry(){
System.out.println("the bloom is dry.");
setChanged();
notifyObservers("dry");
}
public void flower(){
System.out.println("the bloom is flowering.");
setChanged();
notifyObservers("flower");
}
}
这里与上面代码不同的是:必须调用serChanged()方法才能改变状态,notifyObservers方法通知观察者时可以加一个参数。
花匠是观察者,实现Observer接口1
2
3
4
5
6
7
8
9
10
11
12
13
14public class Gardener implements Observer {
public void update(Observable o, Object arg) {
if(arg.equals("dry")) water();
if(arg.equals("flower")) happy();
}
private void water(){
System.out.println("The gardener starts to water.");
}
private void happy(){
System.out.println("The gardener becomes happy.");
}
}
这里的update方法会接受两个参数,一个是发生改变的目标对象的引用,另一个是notifyObservers方法传入的参数。
我们测试一下:1
2
3
4
5
6
7
8
9
10public class TestUseJdk {
public static void main(String[] args){
Bloom bloom = new Bloom();
Gardener gardener = new Gardener();
bloom.addObserver(gardener);
bloom.dry();
bloom.flower();
}
}
结果1
2
3
4the bloom is dry.
The gardener starts to water.
the bloom is flowering.
The gardener becomes happy.
如果不进行setChanged()会怎么样?1
2
3
4
5 public void flower(){
System.out.println("the bloom is flowering.");
// setChanged();
notifyObservers("flower");
}
结果:1
2
3the bloom is dry.
The gardener starts to water.
the bloom is flowering.
花匠(观察者)不会收到通知
jdk还提供clearChanged()方法,看看有什么用1
2
3
4
5
6public void flower(){
System.out.println("the bloom is flowering.");
setChanged();
clearChanged();
notifyObservers("flower");
}
结果:1
2
3the bloom is dry.
The gardener starts to water.
the bloom is flowering.
clearChanged()会视为目标对象未发生改变,从而不会给观察者发送通知
事实上,当通知完观察者后会标记自身为未发生改变1
2
3
4
5
6
7
8public void flower(){
System.out.println("the bloom is flowering.");
setChanged();
//hasChanged()方法返回自上次通知完观察者之后是否状态有过改变
System.out.println("before notify:" + hasChanged());
notifyObservers("flower");
System.out.println("after notify:" + hasChanged());
}
结果1
2
3
4the bloom is flowering.
before notify:true
The gardener becomes happy.
after notify:false
本文例子源码 https://github.com/UUNNFLY/design_pattern
参考链接
博客园—《JAVA与模式》之观察者模式
GeeksforGeeks- Java.util.Observable class in Java
Observable (Java Platform SE 7 ) - Oracle Docs