欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JAVA设计模式之观察者模式

程序员文章站 2022-06-19 14:57:44
气象站系统:气象站可以通过物理装置取得气象信息,WeatherData对象可以通过气象站提供的外部接口获取气象信息。 需求:WeatherData获取最新数据时,需要实时更新三个布告板的气象数据。三个布告板分别是:目前状况、气象统计、天气预报。 一、整理分析: 1.WeatherData有三个get ......

气象站系统:气象站可以通过物理装置取得气象信息,WeatherData对象可以通过气象站提供的外部接口获取气象信息。

需求:WeatherData获取最新数据时,需要实时更新三个布告板的气象数据。三个布告板分别是:目前状况、气象统计、天气预报。

 

一、整理分析:

1.WeatherData有三个getter方法getTemperature(),getHumidity(),getPressure()分别获取温度、湿度、气压值;

2.当数据改变时,WeatherData有个方法measurementsChanged()会被调用(我们不关心如何被调用),此时需更新三个布告板的气象信息;

3.系统需可扩展,可随时新增或者删除布告板。

 

第一次尝试:

 1 public class WeatherData {
 2     
 3     public void measurementsChanged() {
 4         float temperature = getTemperature();
 5         float humidity = getHumidity();
 6         float pressure = getPressure();
 7         //目前状况布告板更新
 8         currentConditionsDisplay.update(temperature, humidity, pressure);
 9         //气象统计布告板更新
10         statisticsDisplay.update(temperature, humidity, pressure);
11         //天气预报布告板更新
12         forecastDisplay.update(temperature, humidity, pressure);
13     }
14     
15     //WeatherData的其他方法
16     
17 }

存在的问题:针对实现编程,会难以扩展和维护,如果需要新增或者删除布告板,必须修改该程序。

 

例如报社,订阅报纸后,报社会定期给你邮寄报纸,停止订阅后报社便停止邮寄。我们把报社改称为“主题 Subject”,把订阅者改成为“观察者 Observer”来研究观察者模式。

观察者模式定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变时,它的所有依赖者都会收到通知并自动更新。

主题不需要知道观察者具体是谁,只需要知道观察者实现了Observer接口,并不关心观察者具体做了哪些事,这种交互对象间的松耦合是设计中追求的原则,下面看主题Subject和观察者Observer接口代码:

1 /*观察者*/
2 public interface Observer {
3     public void update(float temp, float humidity, float pressure);
4 }
1 /*主题*/
2 public interface Subject {
3     /*注册成为观察者*/
4     public void registerObserver(Observer o);
5     /*移除观察者*/
6     public void removeObserver(Observer o);
7     /*通知所有观察者*/
8     public void notifyObservers();
9 }   
1 public interface DisplayElement {
2     /**
3      * 布告板都实现该接口,调用display来展示气象信息
4      */
5     public void display();
6 }

现在让WeatherData实现主题接口:

 1 public class WeatherData implements Subject {
 2     private List<Observer> observerList;
 3     private float temperature;
 4     private float humidity;
 5     private float pressure;
 6     
 7     public WeatherData() {
 8         observerList = new ArrayList<Observer>();
 9     }
10     public void registerObserver(Observer o) {
11         observerList.add(o);
12     }
13 
14     public void removeObserver(Observer o) {
15         int i = observerList.indexOf(o);
16         if (i >= 0) {
17             observerList.remove(i);
18             System.out.println(o.getClass().getName() + " is removed.");
19         }
20     }
21 
22     public void notifyObservers() {
23         for (Observer o : observerList) {
24             o.update(temperature, humidity, pressure);
25         }
26     }
27     /*数据更新时,通知所有观察者*/
28     public void measurementsChanged() {
29         notifyObservers();
30     }
31 
32 }

布告板实现观察者接口:

 1 /*目前状况布告板*/
 2 public class CurrentConditionsDisplay implements Observer, DisplayElement {
 3 
 4     private float temperature;
 5     private float humidity;
 6     private Subject weatherData;
 7     
 8     public CurrentConditionsDisplay(Subject subject) {
 9         this.weatherData = subject;
10         weatherData.registerObserver(this);
11     }
12     
13     public void removeObserver() {
14         weatherData.removeObserver(this);
15     }
16 
17     public void update(float temp, float humidity, float pressure) {
18         this.temperature = temp;
19         this.humidity = humidity;
20         display();
21     }
22     
23     public void display() {
24         System.out.println("CurrentConditionsDisplay conditions:" + temperature + "F degrees and " + humidity + "% humidity");
25     }
26 
27 }
28 
29 /*天气预报布告板*/
30 public class ForecastDisplay implements Observer, DisplayElement {
31 
32     private float temperature;
33     private float pressure;
34     private Subject weatherData;
35     
36     public ForecastDisplay(Subject subject) {
37         this.weatherData = subject;
38         weatherData.registerObserver(this);
39     }
40     
41     public void removeObserver() {
42         weatherData.removeObserver(this);
43     }
44 
45     public void update(float temp, float humidity, float pressure) {
46         this.temperature = temp;
47         this.pressure = pressure;
48         display();
49     }
50     
51     public void display() {
52         System.out.println("ForecastDisplay conditions:" + temperature + "F degrees and " + pressure + "Pa");
53     }
54 
55 }
56 
57 /*气象状况布告板略*/

代码测试:

 1 public class ObserverTest {
 2     
 3     @Test
 4     public void test() {
 5         WeatherData weatherDate = new WeatherData();
 6         CurrentConditionsDisplay ccDisplay = new CurrentConditionsDisplay(weatherDate);
 7         ForecastDisplay fcDisplay = new ForecastDisplay(weatherDate);
 8         weatherDate.setMeasurements(12.3f, 38.6f, 130f);
 9         ccDisplay.removeObserver();
10         weatherDate.setMeasurements(12.3f, 38.6f, 130f);
11         fcDisplay.removeObserver();
12         weatherDate.setMeasurements(12.3f, 38.6f, 130f);
13         System.out.println("notify ok");
14     }
15 }

运行结果:

1 CurrentConditionsDisplay conditions:12.3F degrees and 38.6% humidity
2 ForecastDisplay conditions:12.3F degrees and 130.0Pa
3 com.project.design.observer.CurrentConditionsDisplay is removed.
4 ForecastDisplay conditions:12.3F degrees and 130.0Pa
5 com.project.design.observer.ForecastDisplay is removed.
6 notify ok

 

Java JDK中也存在已经定义好的观察者模式,在java.util包中(Observable(主题), Observer(观察者)),大家有兴趣可以自己了解下。java中的观察者可以手动从主题中拉取数据,主题也可以主动去推送数据。