设计模式-观察者

  1. 意图
  2. 例子
  3. 适用性
  4. 结构
  5. 协作
  6. 效果

意图

定义对象间的一种一对多的依赖关系 ,当一个对象的状态发生改变时 , 所有依赖于它的对象都得到通知并被自动更新。

例子

首先定义观察接口

public interface Observer {
void update(Observable o, Object arg);
}

然后创建多个观察者
public class UserObserver implements Observer {
public void update(Observable o, Object arg) {
System.out.println("user:"+arg);
}
}

接下来是被观察者
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;

public Observable() {
obs = new Vector<>();
}

public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}

public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}

public void notifyObservers() {
notifyObservers(null);
}

public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;

synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}

for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}

public synchronized void deleteObservers() {
obs.removeAllElements();
}

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();
}
}

然后继承该类,创建被观察者。这里会发送一条消息
public class Subject extends Observable {
public void sendMessage(String msg) {
this.setChanged();
notifyObservers(msg);
this.clearChanged();
}
}

public class Main {
public static void main(String[] args) {
Observer u1 = new UserObserver();
Observer u2 = new UserObserver();
Subject subject = new Subject();
subject.addObserver(u1);
subject.addObserver(u2);

subject.setMessage("消息1");
subject.setMessage("消息2");
}
}

适用性

  1. 当一个抽象模型有两个方面 , 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  2. 当对一个对象的改变需要同时改变其它对象 , 而不知道具体有多少对象有待改变。
  3. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之 , 你不希望这些对象是紧密耦合的。

结构

github

协作

  • 当 ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
  • 在得到一个具体目标的改变通知后 , ConcreteObserver 对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。

下面的交互图说明了一个目标对象和两个观察者之间的协作 :
github

注意发出改变请求的 Observer对象并不立即更新 , 而是将其推迟到它从目标得到一个通知之后。 Notify不总是由目标对象调用。它也可被一个观察者或其它对象调用 。

效果

Observer模式允许你独立的改变目标和观察者。你可以单独复用目标对象而无需同时复用其观察者, 反之亦然。它也使你可以在不改动目标和其他的观察者的前提下增加观察者。
下面是观察者模式其它一些优缺点 :

  1. 目标和观察者间的抽象耦合
    一个目标所知道的仅仅是它有一系列观察者 , 每个都符合抽象的Observer类的简单接口 。 目标不知道任何一个观察者属于哪一个具体的类 。 这样目标和观察者之间的耦合是抽象的和最小的。
    因为目标和观察者不是紧密耦合的 , 它们可以属于一个系统中的不同抽象层次。一个处于较低层次的目标对象可与一个处于较高层次的观察者通信并通知它 , 这样就保持了系统层次的完整。如果目标和观察者混在一块 , 那么得到的对象要么横贯两个层次 (违反了层次性 ), 要么必须放在这两层的某一层中 (这可能会损害层次抽象 )。
  2. 支持广播通信
    不像通常的请求, 目标发送的通知不需指定它的接收者。通知被自动广播给所有已向该目标对象登记的有关对象。目标对象并不关心到底有多少对象对自己感兴趣 ; 它唯一的责任就是通知它的各观察者。这给了你在任何时刻增加和删除观察者的自由。处理还是忽略一个通知取决于观察者。
  3. 意外的更新
    因为一个观察者并不知道其它观察者的存在 , 它可能对改变目标的最终代价一无所知。在目标上一个看似无害的的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。此外 , 如果依赖准则的定义或维护不当,常常会引起错误的更新 , 这种错误通常很难捕捉。
    简单的更新协议不提供具体细节说明目标中什么被改变了 , 这就使得上述问题更加严重。 如果没有其他协议帮助观察者发现什么发生了改变,它们可能会被迫尽力减少改变。