1.观察者模式介绍
- Subject : 抽象被观察者(Observeable),吧所有观察者对象的医用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象被观察者提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject: 具体的被观察者,将有关状态存入具体的观察者对象,在具体的被观察者内部状态发生变化时,给所有注册的观察者发送通知。
- Observer : 抽象观察者,定义了一个更新接口,使得在得到被观察者的通知时更新自己。
- ConcreteObserver : 具体的观察者,实现了抽象观察者锁定义的接口,用来在收到通知时更新自己。
(注:继承是实线空心三角箭头,实现是虚线空心三角箭头)
2.Demo
自己写了一个javaDemo,在demo文件夹里
public class myClass {
public static void main(String[] args) {
System.out.print("hello world!");
final TestObserverable testObserverable = new TestObserverable();
final TestObserver testObserverOne = new TestObserver("TestObserver1");
final TestObserver testObserverTwo = new TestObserver("TestObserver2");
final TestObserver testObserverThree = new TestObserver("TestObserver3");
//添加观察者到被观察者,等待被观察者有数据变化时去更新所有添加进来的观察者
testObserverable.addObserver(testObserverOne);
testObserverable.addObserver(testObserverTwo);
testObserverable.addObserver(testObserverThree);
ShowChange showChange = new ShowChange();
testObserverOne.setOnDataChangedListener(showChange);
testObserverTwo.setOnDataChangedListener(showChange);
testObserverThree.setOnDataChangedListener(showChange);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// testObserverable.setChanged();
// testObserverable.notifyObservers();
Scanner scanner = new Scanner(System.in);
String inputString = scanner.next();
// testObserverable.notifyObservers(inputString);
testObserverable.notifyObserversDataChange(inputString);
}
});
try {
Thread.sleep(3000);
thread.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static class ShowChange implements TestObserver.onDataChangedListener{
@Override
public void onDadaChange(String name) {
// System.out.print("观察者收到了被观察者的回调!!!!!!!!!!!");
System.out.print("\n" + name + "has reseive TestObserverable notify,no parames");
}
@Override
public void onDadaChange(String name, String result) {
System.out.print("\n" + name + " has reseive TestObserverable notify, result : " + result);
}
}
}
上面是程序入口类,main方法
//具体观察者(TestObserver),实现抽象观察者Observer()
public class TestObserver implements Observer {
private onDataChangedListener mDataChangedListener;
private String mObserverName;
public TestObserver(String name) {
mObserverName = name;
}
@Override
public void update(Observable observable, Object o) {
String result = String.valueOf(o);
// System.out.println(mObserverName + " receive TestObserverable notify");
if (result == null || result == "") {
mDataChangedListener.onDadaChange(mObserverName);
} else {
mDataChangedListener.onDadaChange(mObserverName, result);
}
}
public void setOnDataChangedListener(myClass.ShowChange listener) {
mDataChangedListener = listener;
}
public interface onDataChangedListener {
public void onDadaChange(String name);
public void onDadaChange(String name, String result);
}
}
上面TestObserver是观察者类
//具体被观察者(TestObserverable),继承于抽象被观察者(Observable)
public class TestObserverable extends Observable{
@Override
protected synchronized void setChanged() {
super.setChanged();
}
@Override
public void notifyObservers() {
super.notifyObservers();
}
@Override
public void notifyObservers(Object o) {
super.notifyObservers(o);
}
public void notifyObserversDataChange(String content) {
setChanged();
notifyObservers(content);
}
/**
* 将观察者添加到被观察者中,当被观察者有变化时通知观察者
* @param observer
*/
@Override
public synchronized void addObserver(Observer observer) {
super.addObserver(observer);
}
}
上面TestObserverable是被观察者类
-
MyClass类里面的main方法中实例化多个TestObserver(观察者),并添加到TestObeserverable(被观察者)里面去,
-
然后调用TestObeserverable的notifyObserversDataChange(content)方法,TestObeserverable会先置changed状态值置为true,然后遍历已注册的观察者并通知观察者(观察者被回调update方法),打出相应的log。
-
输入要输入的内容看结果,如下
hello world! I,amGaryCong TestObserver3 has reseive TestObserverable notify, result : I,amGaryCong TestObserver2 has reseive TestObserverable notify, result : I,amGaryCong TestObserver1 has reseive TestObserverable notify, result : I,amGaryCong
3.源码分析
结合上文例子分析 java.util 包下的 Observer 和 Observable 的实现。
接口 Observer
public interface Observer {
void update(Observable o, Object arg);
}
很简单的一个接口,只定义了一个 update() 方法,参数 Observable 和 Object。 Observable o 表示具体的被观察者对象,Object arg 是要传递和更新的数据。
上文 MyTextView 实现该接口,并实现 update() 方法。该方法的作用是当 DataSource 发生数据变化时,会遍历所有已添加的 MyTextView 并调用它们的 update() 方法来更新 UI。
类 Observable
public class Observable { // 1.1 数据是否变化标记 private boolean changed = false; // 1.2 长度自增长数组 private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
// 2.1 添加观察者对象
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
// 2.2 删除观察者对象
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
// 3.1 通知所有观察者
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
// 线程同步
synchronized (this) {
// 3.2 获取是否发生变化的标记
if (!hasChanged())
return;
// 3.3 转化为 Object 数组
arrLocal = obs.toArray();
// 重置标记
clearChanged();
}
// 遍历所有观察者并调用其 update 方法
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
// 删除所有观察者对象
public synchronized void deleteObservers() {
obs.removeAllElements();
}
// 设置标记为 true,表明数据发生了变化且已经通知过
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();
}
}
该类比较简单,按注释顺序来看:
-
两个变量 changed 和 obs。changed是数据是否变化的标记,主要作用是避免重复通知观察者。obs是一个自增长的数组,用来存放具体的观察者对象,也就是实现了 Observer 的实现类。
-
这里有一个知识点:设计模式的 依赖倒置原则:面向接口编程而不是面向具体对象编程。这个 obs 数组存放的是接口类型而不是某个具体实现类型表明了这一点。
-
添加和删除观察者对象的方法就是往数组 obs 添加和删除元素。
-
notifyObservers() 通知所有观察者,可以看到该函数使用了 synchronized 保证线程安全,然后 hasChanged() 获取当前标记状态,如果标记为 false 则 return 不进行通知。
-
那么这个标记什么时候才能为 true 呢?是在该类的子类中,也就是刚才例子中 DataSource 数据源类 updateData() 方法中首先调用 setChanged() 来设置标记为 true,表明数据即将进行更新。
-
之后将数组 obs 转化为 Object 数组,设置标记为 false,然后遍历 obs 数组并调用所有元素的 update() 方法。也就是例子中所有添加进来的 MyTextView 对象的 update() 方法都会被调用,所有 MyTextView 的 text 发生变化。
-
到这里 Observer(抽象观察者) 和 Observable(抽象被观察者)已经分析的差不多了,那么再结合刚才的例子来总结一下:
-
TestObserver 实现 Observer,是具体的观察者。实现方法 update() 来执行具体的逻辑。
-
TestObserverable 继承 Observable,是具体的被观察者。通过 notifyObservers() 方法传递具体数据来实现通知所有观察者,传递的具体逻辑是在父类中实现的。
-
Observable 作为抽象被观察者实现具体的数据传递逻辑,其内部维护了一个标记和具体观察者列表,当数据发生变化时遍历该列表并通过调用 update() 方法来通知具体观察者实现不同的逻辑。
4.在Android中的使用
最典型的就是ListView和Recyclerview的adapter.notifyDataSetChanged() 不浪费篇幅了
https://blog.csdn.net/qq_25806863/article/details/69218968
https://blog.csdn.net/u012124438/article/details/55294914/
都讲解了ListView的Adapter的观察者模式的使用原理。
5.广播就是典型的观察者模式
6.总结
优点
解除了观察者和被观察者的耦合,而且依赖的都是抽象,容易应对业务变化,各自的变化都不会影响另一个。
增强系统灵活性、可拓展性。
缺点
Java中的消息默认是顺序执行,如果一个观察者卡顿,会造成整个系统效率变低,可以考虑异步。
可能会引起无用的操作甚至错误的操作。