观察者模式

观察者模式

定义

观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。

示例

有这样一个场景,侦察兵(Scout)负责侦查附近有没有敌人,如果发现敌人的话,侦察兵就需要通知将军(General)与士兵(Soldier)。当士兵不在需要知道附近是否有敌人时,侦察兵就只需要通知将军。如果参谋长也需要知道侦查结果的话,同样的需要通知参谋长(Gigas)。这就是典型的一对多并且依赖状态的情况,让我们利用观察者模式来实现吧。

设计

首先我们需要设计一个主题接口(Subject),这个接口定义对观察者的添加、删除、通知方法。Scout类实现Subject接口来完成可观察的功能。然后定义Observer接口,该接口定义update方法,用于接收通知,士兵、参谋长、将军分别实现此接口。类图如下:

代码

Subject.java

1
2
3
4
5
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}

Scout.java

1
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
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Scout implements Subject{
private List<Observer> observers = new ArrayList<>();

@Override
public void registerObserver(Observer o) {
observers.add(o);
}

@Override
public void removeObserver(Observer o) {
if(observers.contains(o)) {
observers.remove(o);
}
}

@Override
public void notifyObservers() {
Iterator<Observer> iterable = observers.iterator();
while (iterable.hasNext()) {
Observer o = iterable.next();
o.update("The enemy is coming");
}
}
}

Observer.java

1
2
3
public interface Observer {
public void update(String msg);
}

General.java

1
2
3
4
5
6
public class General implements Observer {
@Override
public void update(String msg) {
System.out.println("General receive : " + msg);
}
}

Gigas.java

1
2
3
4
5
6
public class Gigas implements Observer {
@Override
public void update(String msg) {
System.out.println("Gigas receive : " + msg);
}
}

Soldier.java

1
2
3
4
5
6
public class Soldier implements Observer {
@Override
public void update(String msg) {
System.out.println("Soldier receive : " + msg);
}
}

测试代码

main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Main {

public static void main(String[] args) {
Subject subject = new Scout();
Observer o1 = new General();
Observer o2 = new Soldier();

subject.registerObserver(o1);
subject.registerObserver(o2);
subject.notifyObservers();

System.out.println("-----register Gigas-----");
Observer o3 = new Gigas();
subject.registerObserver(o3);
subject.notifyObservers();

System.out.println("-----remove soldier-----");
subject.removeObserver(o2);
subject.notifyObservers();

}
}

运行结果

总结

观察者模式遵循了针对接口编程,观察者与主题都是接口,主题通过接口通知观察者,观察者通过接口向主题注册,保证了松耦合。同时观察者模式将变化的部分(Observer的注册与移除)抽离出来,有着良好的扩展性与维护性。