你的位置:首页 > ASP.net教程

[ASP.net教程]设计模式学习——观察者模式(Observer Pattern)


0. 前言

  观察者模式在许多地方都能够用到,特别是作为MVC模式的一部分,在MVC中,模型(M):存放数据,视图(V):显示数据。当模型中的数据发生改变时,视图会得到通知,这是典型的观察者模式。

1. 定义

  观察者模式:定义了一对多的关系,一个对象作为主题,它维护了一系列的依赖对象,当主题的状态发生改变时,会自动地通知依赖对象(通常通过调用依赖对象的方法来实现)。

  官方定义:wiki

2. 应用

  这里通过《Head first 设计模式》中的例子来实现观察者模式。这里有一个气象数据和公布栏,当气象数据发生改变时,会通知公布栏,使其更新数据。

 

 

源码:

主题Subject接口:

1 package ObserverPattern;2 3 public interface Subject {4   public void registerObserver( Observer observer );5   public void removeObserver( Observer observer );6   public void notifyObservers();7 }

观察者Observer接口

1 package ObserverPattern;2 3 public interface Observer {4   public void update(Object obj);5 }

 

气象数据实现:

 1 package ObserverPattern; 2  3 import java.util.ArrayList; 4 import java.util.Iterator; 5  6 public class WeatherData implements Subject { 7  8   private ArrayList<Observer> observers = null; 9   private double temperature;10   private double humidity;11   private double pressure;12   13   public WeatherData( )14   {15     observers = new ArrayList<>();16   }17   18   public double getTemperature() {19     return temperature;20   }21 22   public double getHumidity() {23     return humidity;24   }25 26   public double getPressure() {27     return pressure;28   }29 30   public void SetWeather( double temperature, double humidity, double pressure )31   {32     this.temperature = temperature;33     this.humidity = humidity;34     this.pressure = pressure;35     mesurementsChanged();36   }37   38   public void mesurementsChanged()39   {40     notifyObservers();41   }42   43   @Override44   public void registerObserver(Observer observer) {45     observers.add(observer);46   }47 48   @Override49   public void removeObserver(Observer observer) {50     observers.remove(observer);51   }52 53   @Override54   public void notifyObservers() {55     56     for ( Iterator<Observer> iterator = observers.iterator(); iterator.hasNext(); ) {57       Observer observer = (Observer) iterator.next();58       observer.update(this);59     }60   }61 62 }

显示接口:

1 package ObserverPattern;2 3 public interface DisplayBoard {4   public void display();5 }

公布栏实现:

 1 package ObserverPattern; 2  3 public class CurrentWeatherBoard implements Observer, DisplayBoard { 4  5   private double temperature; 6    7   public CurrentWeatherBoard( Subject subject ) { 8     subject.registerObserver(this); 9   }10   11   @Override12   public void update(Object obj) {13     if ( obj instanceof WeatherData ) {14       WeatherData weatherData = (WeatherData)obj;15       this.temperature = weatherData.getTemperature();16       display();17     }18   }19 20   @Override21   public void display() {22     System.out.println(this.getClass().getName() + ":" + this.temperature);23   }24 25 }

 

3. JDK中Observable类分析

  在JDK中提供了Observable类以及Observer接口方便实现观察者模式,但是这里的主题是Observable是一个类,需要通过继承来实现,所以很大的限制了它的使用。

  Observable类的添加观察者方法,通过synchronized实现同步,其Observable内部维护着一个Vector容器,用于存放观察者对象。  

1 public synchronized void addObserver(Observer o) {2     if (o == null)3       throw new NullPointerException();4     if (!obs.contains(o)) {5       obs.addElement(o);6     }7   }

   

  通知函数,这里会判断一个标识,所以在调用通知时需要先调用 setChanged 方法,然后将其观察者保存到一个数组中,这里会有一个问题,即当调用删除一个观察者的时候,如果正在调用notifyObservers时,依然会通知到被删除的观察者。对于添加来说也是一样的,会错过这一次的通知。

 1 public void notifyObservers(Object arg) { 2  3     Object[] arrLocal; 4  5     synchronized (this) { 6       if (!changed) 7         return; 8       arrLocal = obs.toArray(); 9       clearChanged();10     }11 12     for (int i = arrLocal.length-1; i>=0; i--)13       ((Observer)arrLocal[i]).update(this, arg);14   }