设计模式 - 观察者模式

概述


很早以前,当一个对象的行为依赖于另一个对象的状态时,只能开启一个线程不断的监听对象所依赖的状态。比如通过Callable线程的call()方法获取线程的返回值。当调用Future接口的get()方法时,程序会阻塞在那里,直到拿到线程的执行结果。这种方法虽然可行,但是会给系统带来额外的线程开销,在一个复杂的系统中,这种开销不可小视。观察者模式可以在单线程中使某一对象及时得知自身所依赖的状态的变化。以下是观察者模式经典结构图:

ISubject是被观察对象,可以增加或删除观察者。IObserver是观察者,它监听被观察者的状态变化。当ISubject状态发生变化时,会通过inform()方法通知观察者。
观察者模式角色如下:
  • 主题接口:被观察的对象,接口定义了新增观察者、删除观察者和通知观察者等方法(ISubject)。
  • 具体主题:实现主题接口中的方法。当其状态改变时,它将会通过这个变化通知观察者(ConcreteSubject)。
  • 观察者接口:定义了观察者的基本方法。当依赖状态改变时,主题接口会调用观察者的update方法(IObserver)。
  • 具体观察者:实现观察者接口的update方法(ConcreteObserver)。
简单来说,就是被观察者对象实现主题接口,观察者对象实现观察者接口。仔细观察你会发现,观察者模式其实就是对Java回调机制的运用。

代码示例

主题接口:
package observer;

public interface Isubject{
	// 添加观察者
	public void attach(IObserver observer);
	// 删除观察者
	public void detach(IObserver observer);
	// 通知观察者
	pubic void inform();
}
观察者接口:
package observer;

public interface IObserver{
	// 更新观察者
	public void update(Event event);
}
具体主题:
package observer;

pubic class ConcreteSubject implements ISubject {
	List<IObserver> observers = new ArrayList<>();
	
	public void attach(IObserver observer){
		observers.add(observer);
	}

	public void detach(IObserver observer){
		observers.remove(observer);
	}
	
	public void inform(){
		Event event = new Event();
		for(IObserver observer : observers){
			observer.update(event);
		}
	}
}
具体观察者:
<span style="font-size:14px;">package observer;

public class ConcreteObserver implements IObserver{
	public void update(Event event){
		System.out.println("Received information.");
	}
}</span>
JDK内置的观察者

JDK中已经实现了一套观察者模式。在java.util包中,包括java.util.Observable类和java.util.Observer接口,它们的关系接口图如下:

在java.util.Observable类中,已经实现了主要功能,如增加观察者,删除观察者和通知观察者,开发者可以直接继承Observable类使用这些功能。java.util.Observer接口是观察者接口,观察者对象需要实现Observer接口并实现update方法。
下面是Observable类的内部实现:
package java.util;

public class Observable {
  private boolean changed = false;
  private Vector 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) {
    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();
  }
}








发布了31 篇原创文章 · 获赞 19 · 访问量 10万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章