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所提供的工具,大大简化了开发,其原理和前半部分我们的实现是一样的。