设计模式之禅(2)-观察者模式

版权声明:需要引用、发表的朋友请与本人联系 https://blog.csdn.net/pbrlovejava/article/details/84337687


更多关于设计模式的文章请点击设计模式之禅(0)-目录页


观察者模式是Java标准库的开发中常用的一种设计模式,它完美的将观察者和被观察的对象分离开。当被观察者(主题)改变时,所有观察者(订阅者)都将受到改变的情况,而无论观察者处于什么样的状态。

一、什么是观察者模式

观察者模式Observer Pattern)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

在这里插入图片描述

二、通过设计气象站模块来说明观察者模式

2.1、观察者模式设计的一般类图

在这里插入图片描述

2.2、观察者模式带来的松耦合

当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。
观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

为什么呢?

关于观察者的一切,主题只知道观察者实现了某个接口(也就是Observer接口)。

主题不需要知道观察者的具体类是谁、做了些什么或其他任何细节。
任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者。事实上,在运行时我们可以用新的观察者取代现有的观察者,主题不会受到任何影响。

同样的,也可以在任何时候删除某些观察者。
有新类型的观察者出现时,主题的代码不需要修改。假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题的代码,所有要做的就是在新的类里实现此观察者接口,然后注册为观察者即可。主题不在乎别的,它只会发送通知给所有实现了观察者接口的对象。

我们可以独立地复用主题或观察者。如果我们在其他地方需要使用主题或观察者,可以轻易地复用,因为二者并非紧耦合。

2.3、气象站模块需求

在这里插入图片描述

在这里插入图片描述

2.4、使用观察者模式实现气象站模块

在这里插入图片描述

  • Subject接口
/**
 * @Description: 主题接口
 * @CreateDate: Created in 2018/11/22 11:30
 * @Author: <a href="https://blog.csdn.net/pbrlovejava">arong</a>
 */
public interface Subject {
    //注册观察者
    public void registerObserver(Observer observer);
    //移除观察者
    public void removeObserver(Observer observer);
    //通知所有观察者
    public void notifyObservers();

}
  • Observer接口
/**
 * @Description:   观察者的接口
 * @CreateDate: Created in 2018/11/22 11:32
 * @Author: <a href="https://blog.csdn.net/pbrlovejava">arong</a>
 */
public interface Observer {
    //当气象观测值改变时,主题会把这些状态值当作方法的参数,传送给观察者。
    public void update(float temp,float humidity,float pressure);
}
  • DisplayElement类
/**
 * @Description: DisplayElement接口只包含了一个方法,也就是display()。当布告板需要显示时,调用此方法。
 * @CreateDate: Created in 2018/11/22 11:36
 * @Author: <a href="https://blog.csdn.net/pbrlovejava">arong</a>
 */
public interface DisplayElement {
    public void display();
}
  • WeatherData类
/**
 * @Description:
 * @CreateDate: Created in 2018/11/22 11:38
 * @Author: <a href="https://blog.csdn.net/pbrlovejava">arong</a>
 */
public class WeatherData implements Subject {
    private ArrayList<Observer> observers;
    private float temp;
    private float hudimity;
    private float pressure;

    public WeatherData(){
        observers = new ArrayList<Observer>();
    }


    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        int i = observers.indexOf(observer);
        if(i >= 0){
            observers.remove(observer);
        }else{
            System.out.println("can not delete--该主题没有被该观察者订阅!");
        }
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temp,hudimity,pressure);
        }
    }

    public void changed(){
        notifyObservers();
    }

    public void setMeasurements(float t,float h,float p){
        this.temp = t;
        this.hudimity = h;
        this.pressure = p;
        changed();
    }
}

  • CurrentConditionDisplay类
/**
 * @Description: 当前天气状况公告板
 * @CreateDate: Created in 2018/11/22 11:48
 * @Author: <a href="https://blog.csdn.net/pbrlovejava">arong</a>
 */
public class CurrentConditionDisplay implements Observer,DisplayElement{
    private float temp;
    private float humidity;
    private float pressure;
    private Subject subject;

    public CurrentConditionDisplay(Subject s){
        this.subject = s;
        //在该主题中注册该观察者,接受主题发布的变化
        subject.registerObserver(this);
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temp = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        //更新完毕,输出更新后的状态
        display();
    }

    @Override
    public void display() {
        System.out.println("当前天气状况:");
        System.out.println("temp :"+temp+"\t humidity :"+humidity+"\t pressure :"+pressure);
    }
}
  • 测试气象站模块
/**
 * @Description: 测试观察者模式构建的气象站能否使用
 * @CreateDate: Created in 2018/11/22 11:55
 * @Author: <a href="https://blog.csdn.net/pbrlovejava">arong</a>
 */
public class TestWeatherData {
    @Test
    public void TestObserverPattern(){
        WeatherData weatherData = new WeatherData();
        //三个观察者去订阅weatherData主题,当主题有所改变,观察者会接受到改变
        CurrentConditionDisplay conditionDisplay1 = new CurrentConditionDisplay(weatherData);
        CurrentConditionDisplay conditionDisplay2 = new CurrentConditionDisplay(weatherData);
        CurrentConditionDisplay conditionDisplay3 = new CurrentConditionDisplay(weatherData);
        //主题移除掉一个观察者
        weatherData.removeObserver(conditionDisplay1);
        //更新数据
        weatherData.setMeasurements(1.0f,2.0f,3.0f);
        weatherData.setMeasurements(3.0f,2.0f,1.0f);
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/pbrlovejava/article/details/84337687