1.什么是观察者模式
定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖都会收到通知并自动更新
2.设计原则
a.封装变化
b.多用组合少用继承
c.针对接口编程,不针对实现编程
d.为交互对象之间的松耦合设计而努力
3.代码示例:一个气象站与多个公布板
思路:气象站可以监测当前天气的种种数据,建立一个WeatherData对象,该对象可以注册,移除观察者,并且当从气象站获取数据(使用模拟数据)后,
它会执行相应的方法通知各个观察者,此处的观察者即为布告板
根据针对接口编程的原则,可以建立一个Subject接口,它包含注册,删除,通知观察者三个方法,让weatherData对象去实现它
又因为,布告板即为观察者,为实现解耦,我们应该提供一个统一的通知方法给WeatherData对象,当需要通知观察者时,WeatherData对象不需要关心观察者
都有谁,而是调用统一的方法去通知他们,因此,观察者都应该具有update()方法以便WeatherData对象通知,这是它们的共性,因此单独抽取出来建立一个只含有
update()方法的接口,所有的观察者都因该实现该接口
整理好思路开始编码实现
/* * 被观察者接口 */ public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObserver(); }
/* * 观察者接口 */ public interface Observer { public void update(float temp,float pressure,float humidity); }
/* * 一个实现行为而已 */ public interface DisplayElements { public void display(); }
/* * 被观察者实现 */ public class WeatherData implements Subject { private float temp; private float pressure; private float humidity; private ArrayList observers; public WeatherData() { observers = new ArrayList(); } @Override public void registerObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { int i = observers.indexOf(o); if( i >= 0) { observers.remove(i); } } @Override public void notifyObserver() { for (int i = 0; i < observers.size(); i++) { Observer o = (Observer) observers.get(i); o.update(temp, pressure, humidity); } } /** * 模拟该对象从气象站获取当前天气资料 */ public void getMeasurementData(float temp,float pressure,float humidity) { this.temp = temp; this.pressure = pressure; this.humidity = humidity; //一旦数据更新便通知观察者们 notifyObserver(); } }
/* * 一个观察者的具体实现 */ public class CurrCondition implements Observer,DisplayElements { private float temp; private float pressure; private float humidity; private WeatherData weatherData; public CurrCondition(Subject weatherData) { this.weatherData = (WeatherData) weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("当前温度为 " + this.temp); } @Override public void update(float temp, float pressure, float humidity) { this.temp = temp; this.pressure = pressure; this.humidity = humidity; display(); } }
public class TeatApp { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrCondition currCondition = new CurrCondition(weatherData); weatherData.getMeasurementData(1f, 3.3f,2.09f); weatherData.getMeasurementData(100f, 3.3f,2.09f); } }
总结:
观察者模式的核心同我们简单的接口调用一样,只是我们常用的接口调用的时候常用setXXXXX方法设置一个监听,当监听到的时候我们给设置了监听的一个对象一个回调方法,而观察者模式只是将多个监听对象放到了一个集合里,当变化时给所有的监听对象都回调一下。
4.使用Java提供的观察者实现观察者模式
Java.Util包下有一个observable类和一个observer接口,他们分别是让被观察者和观察者继承从而实现观察者模式。下面是一个很简单的代码。
/* * 被观察者 */ public class Person extends Observable { private String name; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; //标记此 Observable 对象为已改变的对象;现在 hasChanged 方法将返回 true。 this.setChanged(); //如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。 this.notifyObservers(); } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; //标记此 Observable 对象为已改变的对象;现在 hasChanged 方法将返回 true。 this.setChanged(); //如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。 this.notifyObservers(); } }
/* * 观察者 */ public class MyObserver implements Observer { @Override public void update(Observable o, Object arg) { System.out.println("对象发生了改变"); } }
public class TestApp { public static void main(String[] args) { //被观察者对象 Person p = new Person(); //注册观察者 p.addObserver(new MyObserver()); //使对象发生变化 p.setName("Jiaxx3"); p.setSex("woman"); } }
实际中我们可采用jdk所提供的工具,大大简化了开发,其原理和前半部分我们的实现是一样的。