观察者模式

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

这个模式可以通过 报纸订阅服务的过程进行描述:

当订阅者向出版商订阅了某一个杂志之后,只要这个出版商每月出了新的杂志,就会自动把杂志快递给已经向它订阅的用户。

这里的出版商就相当于观察者模式中的“一”,称为主题(Subject),订阅者相当于观察者模式中的“多”,称为观察者(Observer)。

订阅者想要收到每月的新杂志,就必须向出版商进行订阅。出版商只要有新的杂志出版 ,就自动将新的杂志送给订阅者。

下面看一个例子:

我们从气象站,取得天气数据对象 ,我们要把天气数据对象中的天气数据,发送给每个天气布告板。

只要天气数据对象中天气数据一更新,就同步把天气数据更新到天气布告板。

进行抽象 ,这里的天气数据对象就相当于主题,天气布告板就相当于观察者。

类图:

主题接口    Subject接口:

 1 /**
 2  * 这是 主题的接口类   Subject接口   
 3  * @author wly
 4  *
 5  */
 6 public interface Subject {
 7       /**
 8        * 向主题对象 ,注册一个传入的观察者对象  
 9        * @param observer
10        */
11       public  void  registerObserver(Observer  observer);    
12       /**
13        * 从主题对象已经注册的观察者集合中,移除传入的指定的观察者对象
14        * @param observer
15        */
16       public  void  removerObserver(Observer observer);
17       /**
18        * 主题对象调用这个方法,发送消息,通知已经向它注册的观察者对象
19        */
20       public  void  notifyObservers();
21 }

观察者接口   Observer接口:

/**
 * 这是观察者的接口   Observer接口 
 * @author wly
 *
 */
public interface Observer {
      /**
       * 提供一个状态更新的接口 , 在主题对象的notifyObservers()方法中,被调用
       * @param temp     温度
       * @param humidity 湿度
       * @param pressure 气压
       */
      public  void   update(float temp , float humidity , float pressure);
}

具体的主题实现类   WeatherData类:

 1 /**
 2  * 这是具体的主题对象  WeatherData类   
 3  * @author wly
 4  *
 5  */
 6 public class WeatherData implements Subject {
 7     //声明一个list集合     用于存放向主题对象 注册的 观察者对象
 8     private  List<Observer>  observersList ;
 9     //温度变量
10     private  float  temp;
11     //湿度变量
12     private  float  humidity;
13     //气压变量 
14     private  float  pressure;
15     
16     public  WeatherData()
17     {
18         this.observersList = new ArrayList<Observer>();
19     }
20     
21     //注册观察者对象
22     @Override
23     public void registerObserver(Observer observer) {
24         
25         observersList.add(observer);
26     }
27     //移除观察者对象
28     @Override
29     public void removerObserver(Observer observer) {
30          //放回observer对象在 observersList中的索引 ,如果存在返回索引值,不存在返回-1
31          int  i = observersList.indexOf(observer);
32          if(i >= 0)
33          {
34              observersList.remove(i);
35          }
36     }
37     //通知已经注册了观察者对象  
38     @Override
39     public void notifyObservers() {
40         for(int i = 0 ; i < observersList.size() ; i++)
41         {
42             Observer  observer  = observersList.get(i);
43             observer.update(temp, humidity, pressure);
44         }
45     }
46     //模拟测量值变化  ,变化之后通知已经注册了观察者对象
47     public void  setMeasure(float  temp,float  humidity,float  pressure)
48     {
49         this.temp = temp;
50         this.humidity = humidity;
51         this.pressure = pressure;
52         
53         notifyObservers();
54     }
55 }

具体的观察者实现类   布告板  CurrentConditionDisplay类:

 1 /**
 2  * 这是观察者对象   天气情况布告板   CurrentConditionDisplay类  
 3  * @author wly
 4  *
 5  */
 6 public class CurrentConditionDisplay implements Observer {
 7     private  float  temp;        //温度 
 8     private  float  humidity;    //湿度
 9     private  float  pressure;    //气压
10     
11     @Override
12     public void update(float temp, float humidity, float pressure) {
13          this.temp = temp;
14          this.humidity = humidity;
15          this.pressure = pressure;
16     }
17     
18     //布告板的显示信息
19     public  void  display()
20     {
21         System.out.println("当前天气情况如下:");
22         System.out.println("温度:"+temp);
23         System.out.println("湿度:"+humidity);
24         System.out.println("气压:"+pressure);
25     }
26 }

最后提供一个测试类:

 1 public class TestClass {
 2     
 3      public static void main(String[] args) {
 4            //创建两个观察者对象    布告板1 和 布告板2
 5            CurrentConditionDisplay  ccd1  = new  CurrentConditionDisplay();
 6            CurrentConditionDisplay  ccd2  = new  CurrentConditionDisplay();
 7            
 8            //创建一个主题对象   天气数据对象
 9            WeatherData  wd = new WeatherData();
10            //将两个观察者对象布告板 向主题对象进行注册
11            wd.registerObserver(ccd1);
12            wd.registerObserver(ccd2);
13            //模拟 天气数据变化
14            wd.setMeasure(25.2F, 36.6F, 82.9F);
15            
16            //显示布告板的天气信息 
17            ccd1.display();
18            ccd2.display();
19            
20     }
21 }

 运行结果如下:

在JDK中内置类 一个Observerable类 和  Observer接口 。

其中这里的Observerable类相当于我们所写的 Subject接口。  Observerable类已经提供了 注册,移除,通知等方法。

我们在定义一个具体主题类时,直接继承Observerable类就可以继承那些方法,不需要自己写。

Observer接口就相当于我们所写的 Observer接口,这个接口中只有一个update方法,供具体的观察者类去实现。

原文地址:https://www.cnblogs.com/wangliyue/p/4178028.html