什么是观察者模式?
观察者模式是一种不同对象之间交互的模式。它定义了对象间一对多的依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会得到通知并自动更新。而且这些观察者之间没有相互联系,可以根据需求增加或者删除观察者,使得系统更易于扩展。这种模式也被称作发布-订阅模式。
为什么要使用观察者模式?
软件开发过程中我们经常有这种需求:我们要设计一个自动部属的功能,当文件内容发生改变的时候,我们就把修改的文件部属到服务器中。
这个案例中,一个对象要时刻监听着另一个对象,只要被观察者的状态一改变,观察者就要随之做出相应的改变。
那么用什么方法可以做到这种及时反馈呢?从常识来看大概有两种思路。
第一种思路,观察者每隔一段时间就去查一下被观察者有没有更新,但这种方法明显不可行,我们不知道被观察者多久会更新一次,一直去检查被观察者有没有更新是极其消耗资源的一件事。
第二种思路,把主动权给被观察者,让它来通知所有对它的状态改变感兴趣的对象,即观察者。无论从哪方面讲,把主动权交给被观察者都是更正确的选择。
如何使用观察者模式?
观察者模式的核心是让被观察者持有所有观察者的引用。
在观察者模式中,有四种角色:
被观察者接口:持有一个被观察者的容器,这个容器是被观察者的核心,其次还有三个方法,分别是添加方法,删除方法以及通知方法。
具体被观察者实现:包含了具体的数据,并且实现了接口中的具体方法。当状态改变的时候通知注册的观察者。
观察者接口:该接口声明了更新数据的方法update()
,又称为抽象方法。
具体观察者实现:实现了观察者接口的方法,即在被观察对象的状态发生改变后,当前对象如何随之改变。
具体的代码实现步骤可以总结为下面5步。
- 定义观察者接口
// 观察者接口
public interface IObserver {
public void update();
}
- 定义被观察者接口/抽象类
public abstract class ISubject {
private List<IObserver> observers = new ArrayList<>();
// 注册新observer的方法
public void addObserver(IObserver ob) {
this.observers.add(ob);
}
// 删除observer的方法
public void delObserver(IObserver ob) {
this.observers.remove(ob);
}
// 通知方法
public void notifyObservers() {
for(IObserver ob: this.observers) {
ob.update();
}
}
}
- 具体的被观察者
public class ConcreteSubject extends ISubject {
public void somethingHappen() {
// 改变状态
super.notifyObservers();
}
}
- 具体的观察者
public class ConcreteObserver1 implements IObserver {
@Override
public void update() {
System.out.println("Observer 1 updated...");
}
}
public class ConcreteObserver2 implements IObserver {
@Override
public void update() {
System.out.println("Observer 2 updated...");
}
}
- 客户端组织观察者与被观察者
public class Main {
public static void main(String[] args) {
// 初始化观察者与被观察者
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver1 observer1 = new ConcreteObserver1();
ConcreteObserver2 observer2 = new ConcreteObserver2();
// 注册观察者
subject.addObserver(observer1);
subject.addObserver(observer2);
// 被观察者状态改变,所有观察者自动被通知
subject.somethingHappen();
}
}
总结
观察者模式的优点
- 首先建立了一套触发机制,避免了观察者主动去查询被观察者的状态,节约了系统资源
- 观察者模式在观察者与被观察者之间建立了一个抽象的耦合。
观察者模式的缺点
- 由于通知的发布是串行执行的,即执行完一个观察者的
update()
方法才回去执行下一个观察者的方法,当观察者模式很多的情况下,通知的发布会花费很长时间,影响程序效率。 - 观察者模式不能让观察者知道被观察者的状态改变的细节,只知道最后的结果。