观察者模式是一种行为型模式,适用于对象间一对多的依赖关系,其中一是被观察者,多是观察者,观察者依赖于被观察者。
实例:
以天气的情景做例子:第三方天气软件从气象站获取最新的温度,湿度和气压,当气象站温度,湿度和气压变化时,第三方天气软件要做到及时的更新。在不使用观察者模式时,类图结果是这样的:
![](https://img.haomeiwen.com/i14771088/cfc19bba10c483c0.png)
在这个类图结果中,气象站维护了温度,湿度,气压数据,同时还要介入第三方软件获取天气数据的接口或者类,当天气数据变化时,对第三方软件一一进行通知。
这个结构的一个明显缺陷是:每接入一个第三方软件,气象站需要做相应的更改,扩展性太差。
观察者模式实现
观察者模式,则是将被观察者看做主题(Subject)类(本例的主题是WeatherStation),第三方天气软件抽象为Observer接口,类图结构如下:
![](https://img.haomeiwen.com/i14771088/24ebe1069ed69f40.png)
这种结构的设计,使得第三方接入变得简单,当有新的第三方软件需要获取天气数据的时候,仅需要实现observer接口,然后注册到主题类中即可,无论接入多少个第三方软件,气象站类不需要做任何的改动。
代码实现:
public class WeatherStation {
List<Observer> observerList;
private float temperature;//气温
private float pressure;//气压
private float humidity;//湿度
public WeatherStation() {
observerList = new ArrayList<Observer>();
}
public void setData(float temerature, float pressure, float humidity) {
this.humidity = humidity;
this.pressure = pressure;
this.temperature = temerature;
noticeThirdParty();//通知第三方
}
private void noticeThirdParty() {
if (observerList != null && observerList.size() > 0) {
for (Observer observer : observerList) {
observer.update(this.temperature, this.pressure, this.humidity);
}
}
}
public void registerObserver(Observer observer) {
observerList.add(observer);
}
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
}
public interface Observer {
public void update(float temperature,float pressure,float humidity);
}
public class XiaomiWeather implements Observer {
private float temperature;//气温
private float pressure;//气压
private float humidity;//湿度
public XiaomiWeather() {
}
@Override
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("xiaomi当前温度:" + temperature);
System.out.println("xiaomi当前湿度:" + humidity);
System.out.println("xiaomi当前气压:" + pressure);
}
}
public class MojiWeather implements Observer {
private float temperature;//气温
private float pressure;//气压
private float humidity;//湿度
public MojiWeather(){
}
@Override
public void update(float temperature, float pressure, float humidity) {
this.temperature=temperature;
this.pressure=pressure;
this.humidity=humidity;
display();
}
public void display(){
System.out.println("moji当前温度:"+temperature);
System.out.println("moji当前湿度:"+humidity);
System.out.println("moji当前气压:"+pressure);
}
}
public class Test {
public static void main(String[] args) {
WeatherStation subject =new WeatherStation();
subject.setData(12,100,20);
MojiWeather mojiWeather = new MojiWeather();
subject.registerObserver(mojiWeather);
XiaomiWeather xiaomiWeather =new XiaomiWeather();
subject.registerObserver(xiaomiWeather);
subject.setData(11,200,44);
}
}
使用java内置的观察者
Observable:类而不是接口(被观察者)
Observer:观察者,是个接口
因此,我们继承java内置的观察者,对代码进行改造
//定义个天气对象
public class WeatherData {
private float temperature;//气温
private float pressure;//气压
private float humidity;//湿度
public WeatherData(float temperature,float pressure,float humidity){
this.temperature = temperature;
this.humidity=humidity;
this.pressure=pressure;
}
public float getTemperature() {
return temperature;
}
public void setTemperature(float temperature) {
this.temperature = temperature;
}
public float getPressure() {
return pressure;
}
public void setPressure(float pressure) {
this.pressure = pressure;
}
public float getHumidity() {
return humidity;
}
public void setHumidity(float humidity) {
this.humidity = humidity;
}
}
//改造被观察者
public class WeatherStation extends Observable {
private WeatherData weatherData;
public WeatherStation( ) {
super();
}
public void setData(WeatherData weatherData ){
this.weatherData = weatherData;
this.setChanged(); //标识数据变化,否则不会通知
super.notifyObservers(weatherData);
}
}
public class MojiWeather implements Observer {
private WeatherData weatherData;
@Override
public void update(Observable o, Object arg) {
if(arg instanceof WeatherData){
this.weatherData =(WeatherData) arg;
display();
}
}
public void display(){
System.out.println("moji当前温度:"+this.weatherData.getTemperature());
System.out.println("moji当前湿度:"+this.weatherData.getHumidity());
System.out.println("moji当前气压:"+this.weatherData.getPressure());
}
}
//改造观察者
public class XiaomiWeather implements Observer {
private WeatherData weatherData;
@Override
public void update(Observable o, Object arg) {
if(arg instanceof WeatherData){
this.weatherData =(WeatherData) arg;
display();
}
}
public void display(){
System.out.println("xiaomi当前温度:"+this.weatherData.getTemperature());
System.out.println("xiaomi当前湿度:"+this.weatherData.getHumidity());
System.out.println("xiaomi当前气压:"+this.weatherData.getPressure());
}
}
//测试
public class Test {
public static void main(String[] args) {
WeatherData weatherData =new WeatherData(10,20,100);
WeatherStation subject= new WeatherStation();
MojiWeather mojiWeather = new MojiWeather();
XiaomiWeather xiaomiWeather = new XiaomiWeather();
subject.addObserver(mojiWeather);
subject.addObserver(xiaomiWeather);
subject.setData(weatherData);
}
}
观察者模式注意点:
1)观察者模式应避免循环引用
2)观察者模式中顺序通知容易造成通知卡死,因为一个通知失败会造成后续通知不执行,可以采用异步通知的方式
3)通知有两种方式,一种是将变化的数据通知给观察者,一种是通知观察者数据已变化,观察者主动去拉取最新的数据。java内置的Observable也提供了这两种方法
![](https://img.haomeiwen.com/i14771088/0021bb005351b300.png)
4)继承了java的Observable对象后,数据变化时,需要主动调用setChanged()方法, 否则不会通知
代码源码参见:https://github.com/jxl198/designPattern/tree/master/observer
网友评论