快速理解观察者模式,原来它还有这么多其他名字
作者:鱼仔
博客首页: https://codeease.top
公众号:Java鱼仔
# (一)什么是观察者模式
我们都关注了某个公众号,当这个公众号发文章时,所有关注它的人都会收到一条消息通知。这种当一个对象被修改时,会自动通知依赖它的对象的动作抽象为设计模式就是观察者模式
# (二)观察者模式中的角色
观察者模式中主要有四个角色:
Subject:被观察对象的抽象类,这个角色还承担了注册观察者和删除观察者的方法。
ConcreteSubject:具体的被观察对象,在开头的例子中,某个公众号就是一个具体的被观察对象。
Observer:观察者的接口,负责接收被观察对象的状态变化并更新。
ConcreteOberver:具体的观察者,在开头的例子中,每个关注公众号的人就是具体的观察者。
# (三)观察者模式的案例
只看概念很难理解这种设计模式究竟是干什么的,接下来就通过一个具体的例子来感受一下,这个例子还是采用文章开头公众号的例子。 首先定义Observer接口,负责更新操作。
public interface Observer {
/**
* 更新操作
* @param subject
*/
public abstract void update(Subject subject);
}
2
3
4
5
6
7
上面代码中的Subject是被观察对象的抽象类,这个类定义了添加观察者、删除观察者、通知观察者的方法,并定义了获取标题和生成文章的两个抽象方法:
public abstract class Subject {
/**
* 记录所有的观察者
*/
private ArrayList<Observer> observers = new ArrayList<>();
/**
* 添加观察者
* @param observer
*/
public void addObservers(Observer observer){
observers.add(observer);
}
/**
* 删除观察者
* @param observer
*/
public void deleteObservers(Observer observer){
observers.remove(observer);
}
/**
* 通知所有的观察者
*/
public void notifyObservers(){
for(Observer observer:observers){
observer.update(this);
}
}
/**
* 获取文章标题
*/
public abstract String getTitle();
/**
* 生成一篇文章
*/
public abstract void createArticle();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
接着定义具体的被观察对象,这里是一个具体的公众号,并实现获取标题和创建文章的抽象方法:
public class ConcreteSubject extends Subject{
private String title;
@Override
public String getTitle() {
return title;
}
@Override
public void createArticle() {
System.out.println("创建了一篇文章");
this.title="这是文章标题";
this.notifyObservers();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
接下来创建两个观察者:
public class OneObserver implements Observer{
@Override
public void update(Subject subject) {
System.out.println("One收到了一篇推送,标题为"+subject.getTitle());
}
}
public class TwoObserver implements Observer{
@Override
public void update(Subject subject) {
System.out.println("Two收到了一篇推送,标题为"+subject.getTitle());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
最后通过Main类进行测试:
public class Main {
public static void main(String[] args) {
//创建具体的被观察者对象
Subject concreteSubject = new ConcreteSubject();
//创建两个具体的观察者
Observer oneObserver = new OneObserver();
Observer twoObserver = new TwoObserver();
//两个具体的观察者关注了被观察者对象
concreteSubject.addObservers(oneObserver);
concreteSubject.addObservers(twoObserver);
//被观察者对象创建了一篇文章
concreteSubject.createArticle();
//第一个观察者取消关注
concreteSubject.deleteObservers(oneObserver);
//被观察者对象又创建了一篇文章
concreteSubject.createArticle();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
最终的运行结果如下:
创建了一篇文章
One收到了一篇推送,标题为这是文章标题
Two收到了一篇推送,标题为这是文章标题
创建了一篇文章
Two收到了一篇推送,标题为这是文章标题
2
3
4
5
# (四)观察者模式在源码中的应用
在JDK的java.util包下,直接提供了观察者模式所需要的Observer和Subject对象。其中Observer对象和我在第三章定义的十分相似:
package java.util;
public interface Observer {
void update(Observable o, Object arg);
}
2
3
4
5
Subject对象在这个包下名称叫做Observable,包含了添加观察者,删除观察者等操作。
package java.util;
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# (五)总结
观察者模式在不同的场景下还有不同的叫法,比如在本文的例子中,观察者模式叫做发布-订阅(publish-Subscribe)模式会更合适;观察者模式还可以叫做源-监听器(Source-Listener)模式,但是不管怎么叫,它的定义都是相同的。