《图解设计模式》读书笔记8-1 Observer模式
Observer模式即观察者模式,该模式中,被观察者的状态发生变化后会通知给观察者。
此模式适用于根据对象状态进行处理的场景。
示例程序
下面代码的功能是:被观察者是一个随机数生成器,有两个观察者,分别以数值形式和图示形式展示被观察者生成的数字。
程序类图
程序
抽象的数字生成器
public abstract class NumberGenerator {
//观察者列表
private ArrayList observers = new ArrayList();
//增加观察者
public void addObserver(Observer observer) {
observers.add(observer);
}
//删除观察者
public void deleteObserver(Observer observer) {
observers.remove(observer);
}
//提醒观察者
public void notifyObservers() {
Iterator it = observers.iterator();
while (it.hasNext()) {
Observer o = (Observer)it.next();
o.update(this);
}
}
public abstract int getNumber();
public abstract void execute();
}
具体的数字生成器
执行execute()
方法后通知观察者
public class RandomNumberGenerator extends NumberGenerator {
private Random random = new Random();
private int number;
public int getNumber() {
return number;
}
public void execute() {
for (int i = 0; i < 20; i++) {
number = random.nextInt(50);
notifyObservers();
}
}
}
观察者接口
public interface Observer {
void update(NumberGenerator generator);
}
观察者(数字形式展示)
public class DigitObserver implements Observer {
public void update(NumberGenerator generator) {
System.out.println("DigitObserver:" + generator.getNumber());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
观察者(图形方式展示)
public class GraphObserver implements Observer {
public void update(NumberGenerator generator) {
System.out.print("GraphObserver:");
int count = generator.getNumber();
for (int i = 0; i < count; i++) {
System.out.print("*");
}
System.out.println("");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
执行
public class Main {
public static void main(String[] args) {
NumberGenerator generator = new RandomNumberGenerator();
Observer observer1 = new DigitObserver();
Observer observer2 = new GraphObserver();
generator.addObserver(observer1);
generator.addObserver(observer2);
generator.execute();
}
}
//结果
DigitObserver:22
GraphObserver:**********************
DigitObserver:11
GraphObserver:***********
DigitObserver:40
GraphObserver:****************************************
DigitObserver:39
GraphObserver:***************************************
DigitObserver:28
GraphObserver:****************************
DigitObserver:23
GraphObserver:***********************
DigitObserver:38
GraphObserver:**************************************
DigitObserver:39
GraphObserver:***************************************
......省略
角色和类图
角色
- Subject:被观察者
被观察者内部维护了一个观察者的list,定义了增加和删除观察者的方法。同时还定义了一个通知观察者的方法,作用是:如果自己内部发生了变化,通知观察者取得这些变化。本例中由NumberGenerator
扮演这个角色。
- ConcreteSubject:具体的被观察者
实现了被观察者的执行方法,在执行过程中调用方法通知观察者。本例中由RandomNumberGenerator
扮演此角色。
- Observer:观察者
声明供被观察者调用的方法,此方法可以获得被观察者状态的变化值。本例中由Observer
接口扮演此角色。
- ConcreteObserver:具体的观察者
实现了观察者接口的方法,通过这个方法可以获得被观察者的值,达到监控的目的。本例中由DigitObserver
和GraphObserver
扮演此角色。
类图
思路拓展
可复用性
对于具体的被观察者和观察者而言,他们之间的关系由他们的父类和接口进行关联。
具体的被观察者RandomNumberGenerator
不需要知道观察者是谁,有多少,它只负责执行时调用通知方法通知观察者即可。
具体的观察者GraphObserver
和DigitObserver
不需要知道是谁实现了NumberGenerator
,只负责拿到值并处理即可。
这样的设计降低了耦合度,提升组件可复用性。其做法的特点是:
利用抽象类和接口从具体类中抽出抽象方法。
将实例作为参数传递至类中,或者在类的字段中保存实例时,不使用具体类型,而是使用抽象类型和接口。
Observer的顺序
如果观察者能够改变被观察者的数据,那就要注意观察者的调用顺序了。还要注意防止循环调用
当Subject发生变化时,通知Observer,Observer改变Subject,Subject发生变化,通知Observer...
MVC模式
Model发生改变时通知View,View根据Model的值显示新的内容。Model就是被观察者,View就是观察者。