在学习观察者模式以前,咱们先了解一下接口回调的概念。二者的原理有些相似,理解了接口回调就很是容易理解观察者模式。java
所谓接口回调通常应用的场合是:你不知道这个方法何时回返回,可是你但愿在该方法结束的时候拿到方法执行的结果。常见的,好比一个方法内部开启了线程,而咱们但愿在线程执行结束的时候拿到线程的执行结果。编程
在下面的例子中,方法 cal()
定义了一个局部变量 i,随后开启了一个线程,并在线程执行的时候修改了 i 的值。咱们但愿在线程执行完毕的时候达到 i 的执行结果。设计模式
public int cal() {
int i;
new Thread(new Runnable() {
Thread.sleep(3000); // throw ... ignore it
i++;
}).start();
return i;
}
复制代码
使用 return 确定不行,由于方法结束时,线程可能尚未结束,那么 return 返回的结果是没法被预料到的,多是线程执行完毕以后的,也多是没有被线程修改就返回了的。异步
咱们可使用接口回调解决这个问题。咱们能够在调用该方法的时候传入一个接口 Callback 的实例。在线程中执行完全部的逻辑以后,咱们使用该接口的 call()
方法将 i 回调出来:ide
public void cal(Callback callback) {
int i;
new Thread(new Runnable() {
Thread.sleep(3000); // throw ... ignore it
i++;
if (callback != null) {
callback.call(i); // 1
}
}).start();
}
复制代码
固然,接口回调更像是将个人 call()
方法注入到了上述代码中的 1 处。这近似于所谓的函数编程的概念,就是将接口做为一个函数注入到了方法中。函数
接口回调有很是丰富的应用场景,典型的是一些异步的场景,好比 “监听” 一个按钮的执行结果等等。性能
好了,了解了上面的接口回调以后,咱们来看下观察者模式。首先,咱们来了解一下观察者设计模式中的一些概念。学习
若是使用 1 中的的例子来作类比的话,那么 i 就是咱们的主题(Subject),咱们进行接口回调的类(将实现的 Callback 传入到 cal 方法时所处的类)叫作观察者(Subscriber)。this
上面的是观察者模式的UML模型。这里的 Subject
接口就是主题的接口,而 ConcreteSubkect
是它的具体实现类,即具体的 主题。Observer
接口是观察者的接口,ConcreteObserver
是具体的观察者。一个主题每每会经过列表来维护一系列的观察者,而后当主题发生变化的时候会便利这个列表来通知全部的观察者。因此,这里的 Subject
接口定义了三个方法,从上到下依次用于向主题中添加观察者,从主题中移除观察者以及通知全部的观察者主题的更新。spa
下面咱们给出一份最简单的观察者设计模式的代码:
1.首先是主题的定义类:
public class ConcreteSubject implements Subject {
// 经过队列维护观察者列表
private List<Observer> observers = new LinkedList<>();
// 注册一个观察者
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
// 移除一个观察者
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(o);
}
}
// 通知全部观察者主题的更新
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.method();
}
}
}
复制代码
2.接下来是观察者的定义类:
public class ConcreteObserver implements Observer {
// 该观察者订阅的主题
private Subject subject;
public ConcreteObserver(Subject subject) {
this.subject = subject;
// 将当前观察者添加到主题订阅列表中
subject.registerObserver(this);
}
// 当主题发生变化的时候,主题会遍历观察者列表并经过调用该方法来通知观察者
@Override
public void method() {
// ...
}
}
复制代码
上面就是观察者的基本的实现方式,这里的实现逻辑比较简单,但当你学习更加复杂的观察者设计的以前理解它是颇有必要的。
观察者与被观察者之间是属于轻度的关联关系,而且是抽象耦合的,这样,对于二者来讲都比较容易进行扩展。
观察者模式是一种经常使用的触发机制,它造成一条触发链,依次对各个观察者的方法进行处理。但同时,这也算是观察者模式一个缺点,因为是链式触发,当观察者比较多的时候,性能问题是比较使人担心的。而且,在链式结构中,比较容易出现循环引用的错误,形成系统假死。而且由于观察者列表中维护了一份观察者的引用,当它们没有被及时地释放的话,可能会引发内存泄漏。