花瓣小跑 发表于 2023-10-14 21:12:06

观察者模式

观察者模式

案例引入

要求

气象站案例要求

[*]1.气象站,可以将每天测量到的湿度,温度,气压等气象信息以公告的形式发布出去(发布到自己的网站或者第三方平台)。
[*]2.需要设计开发新的api,便于其他第三方也能接入气象站的数据。
[*]3.提供温度,气压,湿度的接口。
[*]4.策略的数据更新后,实时的通知第三方。
普通方案实现案例

通过对气象项目的分析,我们可以初步设计一个WeatherData类。有温度(temperature),湿度(humidity),气压(pressure)三个属性,还有dataChange方法。

[*]1.通过getXxx方法,可以让第三方接入,并得到相关信息。
[*]2.气象站定时的调用dataChange()去更新数据,在数据更新时,当第三方再次获取时,就能得到最新的数据,当然也可以推送数据,即定时的将数据,推送到目标网站上。
代码实现

/**
* 1.核心类,包含最新的天气信息数据,可以推送给别人
* 2.含有 private CurrentConditions currentConditions;
* 3.数据更新时,主动调用currentConditions进行数据推送,这样接入方,就会及时看到最新数据
*
* @author 长名06
* @version 1.0
*/
public class WeatherData {

    //温度
    private float temperature;
    //气压
    private float pressure;
    //湿度
    private float humidity;

    private CurrentConditions currentConditions;

    public WeatherData(CurrentConditions c) {
      this.currentConditions = c;
    }

    public float getTemperature() {
      return temperature;
    }

    public float getPressure() {
      return pressure;
    }

    public float getHumidity() {
      return humidity;
    }

    public void dataChange() {
      currentConditions.update(getTemperature(), getPressure(), getHumidity());
    }

    //当数据有更新时,就调用这个setData
    public void setData(float temperature, float pressure, float humidity) {
      this.temperature = temperature;
      this.pressure = pressure;
      this.humidity = humidity;
      //信息改变时,将最新信息,推送给接入方
      dataChange();
    }
}
/**
* 显示今天天气情况,气象站自己的网站
* @author 长名06
* @version 1.0
*/
public class CurrentConditions {

    //温度
    private float temperature;
    //气压
    private float pressure;
    //湿度
    private float humidity;

    //更新数据 由WeatherData来调用,
    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("今天温度" + temperature);
      System.out.println("今天气压" + pressure);
      System.out.println("今天湿度" + humidity);
    }
}
/**
* 观察者模式
* @author 长名06
* @version 1.0
*/
public class Client {
    public static void main(String[] args) {
      CurrentConditions currentConditions = new CurrentConditions();
      WeatherData weatherData = new WeatherData(currentConditions);


      weatherData.setData(30,100,25);
      System.out.println("=====天气变化=====");
      weatherData.setData(35,100,30);
    }
}问题分析


[*]1.无法在运行时,动态的添加第三方。
[*]2.在WeatherData中,当增加一个第三方,都需要创建一个对应的第三方的公告板对象,并加入到dataChange,不利于维护,也不是动态加入。
[*]3.违反了ocp(开闭原则),=> 使用观察者模式。
观察者模式原理

观察者模式,类似订牛奶的业务,在观察者模式下,有以下角色,奶站/气象局(Subject),用户/第三方网站(Observer),Subject中有登记注册,移除和通知接口方法,register()注册,remove()移除,notify()通知注册用户,根据不同需求,不同实现,可以通知用户取数据,也可以推送给用户数据,也可以更新数据,Observer中接收输入,也就是修改数据的方法update()。
观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer数据变化,类似定牛奶的业务,Subject是1,Observer是多。
观察者模式实现案例

uml图

https://img2023.cnblogs.com/blog/2883613/202310/2883613-20231005222946045-1400737091.png
代码实现

/**
* @author 长名06
* @version 1.0
*/
public interface Subject {

    public void register(Observer o);

    public void remove(Observer o);

    public void notifies();

}
public interface Observer {

    public void update(float temperature,float pressure,float humidity);

}
/**
*1.核心类,包含最新的天气信息数据,可以推送给别人
*2.含有 观察者集合。使用ArrayList管理
*3.数据更新时,主动调用观察者集合进行数据推送,这样接入方,就会及时看到最新数据
* @author 长名06
* @version 1.0
*/
public class WeatherData implements Subject{

    //温度
    private float temperature;
    //气压
    private float pressure;
    //湿度
    private float humidity;

    private List<Observer> observers = new ArrayList<>();

    public float getTemperature() {
      return temperature;
    }

    public float getPressure() {
      return pressure;
    }

    public float getHumidity() {
      return humidity;
    }

    public void dataChange(){
      notifies();//通知所有注册用户
    }

    //当数据有更新时,就调用这个setData
    public void setData(float temperature, float pressure, float humidity) {
      this.temperature = temperature;
      this.pressure = pressure;
      this.humidity = humidity;
      //信息改变时,将最新信息,推送给接入方
      dataChange();
    }

    @Override
    public void register(Observer o) {
      observers.add(o);
    }

    @Override
    public void remove(Observer o) {
      if(observers.contains(o)) {
            observers.remove(o);
      }
    }

    @Override
    public void notifies() {
      for(Observer o : observers){
            o.update(this.temperature,this.pressure,this.humidity);
      }
    }
}
public class TenXun implements Observer{
    //温度
    private float temperature;
    //气压
    private float pressure;
    //湿度
    private float humidity;

    //更新数据 由WeatherData来调用,
    @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("====腾讯网站====");
      System.out.println("腾讯 今天温度" + temperature);
      System.out.println("腾讯 今天气压" + pressure);
      System.out.println("腾讯 今天湿度" + humidity);
    }
}
/**
* @author 长名06
* @version 1.0
*/
public class XingLang implements Observer{

    //温度
    private float temperature;
    //气压
    private float pressure;
    //湿度
    private float humidity;

    //更新数据 由WeatherData来调用,
    @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("====新浪网站====");
      System.out.println("新浪 今天温度" + temperature);
      System.out.println("新浪 今天气压" + pressure);
      System.out.println("新浪 今天湿度" + humidity);
    }
}
public class Baidu implements Observer {
    //温度
    private float temperature;
    //气压
    private float pressure;
    //湿度
    private float humidity;

    //更新数据 由WeatherData来调用,
    @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("====百度网站====");
      System.out.println("百度 今天温度" + temperature);
      System.out.println("百度 今天气压" + pressure);
      System.out.println("百度 今天湿度" + humidity);
    }

}
/**
* @author 长名06
* @version 1.0
*/
public class Client {
    public static void main(String[] args) {
      WeatherData weatherData = new WeatherData();

      Baidu baidu = new Baidu();
      TenXun tenXun = new TenXun();
      XingLang xingLang = new XingLang();

      weatherData.register(baidu);
      weatherData.register(tenXun);
      weatherData.register(xingLang);

      weatherData.setData(20,100,30.3F);

      weatherData.remove(xingLang);

      System.out.println("====某个用户不订阅了====");
      weatherData.setData(20,100,30.3F);
    }
}观察者模式优势

1.使用观察者模式后,以集合的形式来管理用户(Observer),包括注册,移除和通知。
2.这样我们增加观察者(可以理解为一个新的用户),就不需要取修改核心类,WeatherData不用修改代码,遵守了ocp。
观察者模式在JDK源码分析

1.JDK的ObServable类就使用了观察者模式。
https://img2023.cnblogs.com/blog/2883613/202310/2883613-20231005223254476-1675113535.png
https://img2023.cnblogs.com/blog/2883613/202310/2883613-20231005223300316-704950876.png
2.角色分析
​        2.1 Observable的作用和地位等价于我们前面讲过的Subject.
​        2.2 Observable是类,不是接口,类中也实现了核心的方法,即管理Observable的方法,add,remove,notify等。
​        2.3 Observer的作用和地位等价于我们前面讲过的Observer,有update。
​        2.4 Observable和Observer的使用方法和前面讲过的一样,只是Observable是类,通过继承来实现观察者模式。
只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 观察者模式