0
点赞
收藏
分享

微信扫一扫

HeadFirst设计模式之观察者模式

昨天总结消化了策略模式,需要看的同学可以看我的设计模式的上篇博文。今天我们继续来讲解HeadFirst里面的观察者模式。首先给出观察者模式的定义。

观察者模式

定义:

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

观察者模式其实就是 出版者(Subject) + 订阅者(Observer) = 观察者模式(observer pattern)
其类图如下:
在这里插入图片描述
如类图中所示,观察者模式中有如下角色:

  • Subject接口:抽象主题也就是我们公式中的出版者,抽象主题角色把观察者对象保存在一个集合中,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和移除观察者对象。
  • ConcreteSubject:具体被观察主题,该具体主题将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有内部注册的观察者发送通知,并调用它们的update()方法。
  • Observer:抽象观察者接口,定义了一个更新接口,使得在得到主题更改通知的时候改变自身状态。
  • ConcreteObserver:具体观察者,实现抽象贯彻着定义的更新接口,以便在得到主题更改通知时更新自身状态。

观察者模式实现案例

现在我们有如下需求,我们需要建造一个气象站,使用WeatherData对象来负责跟踪目前的天气情况(温度,湿度,气压)。现在我们有三种布告板用来实时跟踪显示检测到的天气情况,并且这必须要是一个可以扩展的气象站,因为我们可能额外的增加更多的布告板。
该案例就非常适用我们的观察者模式了:

public interface WeatherData {

    void getTemperature();
    void getHumidity();
    void getPressure(); //以上三个方法各自返回最近的气象检测数据,
    //我们不在乎这些变量如何被设置,我们只关心如何趋势线当测量更改之后,
    //让布告板实时更新
    void measureMentsChanged();
}

下面让我们来使用观察者模式,我们首先根据类图来实现主题接口

public interface Subject{
	void registerObserver(Observer o);
	void removeObserver(Observer o);  //以上两个方法都需要一个观察者作为变量,
	//该观察者使用来注册或被删除的。
	void notifyObservers(Observer o);//当主题状态改变时这个方法会被调用,以通知所有的观察者。
}

下面定义Observer接口

public interface Observer{
	void update(float temp,float humidity,float pressure);//当气象观测值改变时,主题会把这些状态当做
	//方法的参数,传递给观察者。所有的观察者都必须实现update()方法,已实现观察者接口。
}

下面定义布告板接口

public interface DisplayElement{
	void display(); //DisplayElement接口只包含了一个方法,
	//也就是display()。当布告板需要显示时调用此方法。
}

下面我们对WeatherData进行实现,这也是我们的具体实现Subject

public class WeatherData implements Subject{ //weatherData是具体的被观察对象因此实现了Subject接口
    private ArrayList<Observer> observers; //使用此列表来记录所有观察该主题的观察者
    private float temperature;
    private float humidity;
    private float pressure;
    public WeatherData(){
        observers = new ArrayList<>();
    }


    @Override
    public void registerObserver(Observer o) {
        observers.add(o);   //当有新的观察者来观察该主题的时候,将该观察者注册进观察该主题的观察者列表
    }

    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if(i >= 0){
            observers.remove(o);            //当某观察者不想再观察该主题了,就将观察者删除即可
        }
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature,humidity,pressure); //该方法通知所有的观察者,也就是调用它们的update方法
        }
    }

    public void messurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature,float humidity,float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        messurementsChanged();
    }
}

然后对具体观察者进行实现

public class CurrentConditionsDisplay implements Observer,DisplayElement { //此布告板实现了Observer接口,所以可以从WeatherData中活的改变,也实现了布告板接口
    private  float temperature;
    private float humidiity;
    private float pressure;
    private Subject weatherData;

    public CurrentConditionsDisplay(WeatherData weatherData) { //weatherdata对象 作为注册之用
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("Current conditions:" + temperature + "F degrees and pressure:" + pressure + "humidity:"+ humidiity);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) { //当update被调用的时候,我们吧这些数据保存起来,然后调用display进行展示
        this.temperature = temperature;
        this.humidiity = humidity;
        this.pressure = pressure;
        display();
    }
 }

我们通过一个具体的测试程序来进行测试:

public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay firstDisplay = new CurrentConditionsDisplay(weatherData); //观察者 会被注册到观察者列表
        //secondDisplay thirdDisplay也都意向,代表三个具体的观察者,我没进行实现,与firstDisplay类似
        weatherData.setMeasurements(80,65,30.4f);//模拟测量数据发生变化
        weatherData.setMeasurements(70,65,30.4f);
        weatherData.setMeasurements(30,65,30.4f);
    }

}
--------------------------
运行结果:
Current conditions:80.0F degrees and pressure:30.4humidity:65.0
Current conditions:70.0F degrees and pressure:30.4humidity:65.0
Current conditions:30.0F degrees and pressure:30.4humidity:65.0

通过上面我们可以看到,当我们的Subject发生改变的时候,观察者立马收到了通知,知道了关注的Subject中数据发生了改变。

以上是我自己实现的观察者模式,起始Java API内给我们内置了观察者模式,就在java.util包中。 两个相关的结构分别是Observer接口与Observale类,这和我们自己实现的Subject接口与Observer类似,很多功能java api已经帮我们准备好了,我们可以风方便的使用。

被观察Subject
被观察Subject
观察者Observer
在这里插入图片描述
感兴趣的同学可以自己使用java.util包中帮我们提供的api进行实现。

总结一下

观察者模式提供了一种对象设计,能够让主题和观察者之间松耦合,关于观察者的一切,主题只知道观察者实现了某个接口(也就是Observer接口)。主题不需要知道观察者的具体类是谁,做了些什么或其他的任何细节。主题依赖于接口,而不依赖于具体的实现,我们可以随时的增加观察者,而其他的观察者和主题不会受到任何影响,同时当我们新增观察者的时候也不需要修改代码,因此可以独立的复用主题和观察者,两者并非紧耦合,而使一种松耦合的(改变一方并不会影响另外一方。)
好啦,今天的观察者模式讲完了,如果想要了解更多的设计模式,请关注我哦~

举报

相关推荐

0 条评论