观察者模式用于建立对象与对象之前的依赖关系。一个对象发送改变的时将自动通知其他对象,其他对象将相应做出反应。发生改变的对象称为观察目标,而被通知的对象称为观察者。
观察者模式的定义
观察者模式定义对象的之前的一种一对多的依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
其UML类图如下所示:
由图可以看出观察者模式包含了以下四个角色:
(1)Subject(目标):它是指被观察的对象。在目标中定义了一个观察者集合,一个观察者集合可以接收任意数量的观察者来进行观察。同时定义了通知方法notify()。
(2) ConcreteSubject(具体目标):是目标类的子类。当他的状态发生改变的时候,向其各个观察者发出通知。
(3)Observer(观察者):观察者将对观察目标的改变做出反应。
(4)ConcreteObserver(具体观察者):存储了具体观察者的有关状态,这些状态和具体目标的状态保持一致。
观察者模式包含观察目标和观察者两类对象,一旦观察目标的状态发生改变,所有的观察者都将收到通知。
其典型代码如下:
import java.util.*;
abstract class Subject{
//定义一个观察者集合用于存储所有的观察者对象
protected ArrayList observers<Observer> = new ArrayList();
//注册方法,用于向观察者集合中增加一个观察者
public void attach(Observer observer){
observers.add(observer);
}
//注销方法,用于在观察者集合中删除一个观察者
public void detach(Observer observer){
observers.remove(observer);
}
//声明抽象通知方法
public abstract void notify();
}
具体目标类的典型代码
class ConcreteSubject extends Subject{
//实现通知方法
public void notify(){
//遍历观察者集合 调用每一个观察者的响应方法
for(Object obs:observers){
((Observer)obs).update();
}
}
}
抽象观察者角色典型代码
interface Observer{
//声明响应方法
public void update();
}
具体观察者
class ConcreteObserver implements Observer{
//实现响应方法
public void update(){
//具体响应代码
}
}
在一些复杂的情况下,具体观察者类ConcreteObserver的update()方法在执行的时候需要使用到具体目标类的ConcreteSubject中的状态。因此在ConcreteObserver与ConcreteSubject之前有时候还存在关联或依赖关系。
JDK中的观察者模式
在jdk中提供了Observer和Observable来实现对观察者模式的支持
Observer接口
在该接口中只声明一个方法update(Observable o,Object arg);
当观察目标的状态发生变化时,该方法就会被调用
Observable接口
用来充当观察目标类,定义了一个向量Vector来存储观察者对象。其中包含了许多方法,不在此进行累述了。
观察者模式总结
观察者模式为实现对象之前的联动提供了一套完整的解决方案。凡是涉及一对一或一对多的对象交互场景都可以使用观察者模式。
观察者模式的优点
(1)实现表示出和数据逻辑层的分离。
(2)在观察目标和观察者之前建立了一个抽象的耦合.
(3)满足开闭原则的要求
观察者模式的缺点
(1)如果观察者模式和观察目标之前存在循环依赖,会触发循环调用,导致系统崩溃
(2)如果存在很多的观察者,将所有的观察者都进行通知会花费很多时间。
适用场景
(1)一个对象的改变将导致一个或多个其他对象发生改变,而不知道具体有多少对象将发生改变,也不知道这些对象是谁
(2)需要在系统中创建一个触发链,A对象行为影响B,B对象行为影响C,可以使用观察者模式