设计模式——观察者模式 Java源代码

本程序改编自《Head First Design Patterns》上关于气象站的例子,我将例子进行了化简。

总共7个java源文件

一个Subject接口
一个Observer接口
一个DisplayElement接口
一个Subject具体类,实现Subject接口
两个Observer具体类,实现Observer和DisplayElement接口
一个Main类,用于测试

观察者模式类图
这里写图片描述
图:我用插件画的类图

The Observation Pattern defines a one-to-many dependency。这里的one就是Subject, many就是Observers;one就是发布者,many就是订阅者;one就是事件源,many就是监听者。


Talk is cheap, show me the code

一个Subject接口

package observer;

public interface Subject
{
    public void registerObserver(Observer o);
    public void removeOvserver(Observer o);
    public void notifyObservers();
}

一个Observer接口

package observer;

public interface Observer
{
    public void update(double temperature, double humidity, String condition);
}

一个DisplayElement接口

这个接口只有display( )一个抽象方法,其实如果放在Observer里面的话,仅从代码层面考虑的话,也可以。但是如果从逻辑层面考虑的话,最好还是分开。毕竟这个display和观察者是”两码事“,不要耦合在一起。《Head First Design Pattern》上面的例子代码这样写,是为了描绘出一个生动形象的”气象站“的例子,来帮助大家理解观察者模式。

package observer;

public interface DisplayElement
{
    public void display();
}

一个Subject具体类

package observer;

import java.util.ArrayList;
             // Subject收集天气信息,然后通知Observers
public class WeatherData implements Subject
{
    private ArrayList<Observer> observers;
    private double temperature;
    private double humidity;
    private String condition;

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

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

    @Override
    public void removeOvserver(Observer o)
    {
        int i = observers.indexOf(o);
        if(i>=0)
        {
            observers.remove(i);
        }
    }

    @Override
    public void notifyObservers()
    {
        for(Observer observer : observers)
        {
            observer.update(temperature, humidity, condition);
        }
    }

    public void measurementsChanged()
    {
        notifyObservers();
    }

    public void setMeasurements(double temperature, double humidity, String condition)
    {
        this.temperature = temperature;
        this.humidity = humidity;
        this.condition = condition;
        measurementsChanged();
    }

    public double getTemperature()
    {
        return temperature;
    }

    public double getHumidity()
    {
        return humidity;
    }

    public String getPressure()
    {
        return condition;
    }

}

两个Observer具体类

package observer;
             // 显示当前天气情况
public class CurrentDisplay implements Observer, DisplayElement
{
    private double temperature;
    private double humidity;
    private String condition;

    public CurrentDisplay(Subject weatherData)
    {
        weatherData.registerObserver(this);
    }

    @Override
    public void display()
    {
        System.out.println("Current Conditions: "+ temperature + " C degrees and "
                + humidity + "% humidity " +  condition );
    }

    @Override
    public void update(double temperature, double humidity, String condition)
    {
        this.temperature = temperature;
        this.humidity = humidity;
        this.condition = condition;
        display();
    }

    public String toString()
    {
        return "This is Current Condition Display";
    }
}
package observer;
             // 显示历史统计数据
public class StatisticDisplay implements Observer, DisplayElement
{
    private double maxTemperature = 0;
    private double minTemperature = 100;
    private double temperatureSum = 0;
    private int    totalUpdating = 0;

    public StatisticDisplay(Subject weatherData)
    {
        weatherData.registerObserver(this);
    }

    @Override
    public void display()
    {
        System.out.println("Avg/Max/Min temperture: " + temperatureSum/totalUpdating + "/" 
                + maxTemperature + "/" + minTemperature);
    }

    @Override
    public void update(double temperature, double humidity, String condition)
    {
        temperatureSum += temperature;
        totalUpdating++;
        if(temperature > maxTemperature)
        {
            maxTemperature = temperature;
        }
        if(temperature < minTemperature)
        {
            minTemperature = temperature;
        }
        display();
    }

    public String toString()
    {
        return "This is Statictic Display";
    }
}

一个Main测试类

package observer;

public class Main
{

    public static void main(String[] args)
    {
        WeatherData weatherStation = new WeatherData(); // 一个气象站作为Subject

        CurrentDisplay currentDisplay = new CurrentDisplay(weatherStation);       // 注册Observer1
        System.out.println(currentDisplay);    // 这个是为了不让eclipse报出warning                       
        StatisticDisplay statisticDisplay = new StatisticDisplay(weatherStation); // 注册Observer2
        System.out.println(statisticDisplay);  // 这个是为了不让eclipse报出warning                                   


        weatherStation.setMeasurements(20, 30, "晴天");  // 气象站测量出了新的天气,在第一时间通知所有的观察者
        weatherStation.setMeasurements(16, 50, "多云");
        weatherStation.setMeasurements(12, 60, "大风");
        weatherStation.setMeasurements(12, 90, "小雨");
        weatherStation.setMeasurements(11, 98, "大雨");
    }

}

运行结果

直接从eclipse复制过来

This is Current Condition Display
This is Statictic Display
Current Conditions: 20.0 C degrees and 30.0% humidity 晴天
Avg/Max/Min temperture: 20.0/20.0/20.0
Current Conditions: 16.0 C degrees and 50.0% humidity 多云
Avg/Max/Min temperture: 18.0/20.0/16.0
Current Conditions: 12.0 C degrees and 60.0% humidity 大风
Avg/Max/Min temperture: 16.0/20.0/12.0
Current Conditions: 12.0 C degrees and 90.0% humidity 小雨
Avg/Max/Min temperture: 15.0/20.0/12.0
Current Conditions: 11.0 C degrees and 98.0% humidity 大雨
Avg/Max/Min temperture: 14.2/20.0/11.0


总结

这个观察者模式,多个观察者(Observer)“围观”一个被观察者(Subject),被观察者是万众瞩目的焦点。观察者如果想得到Subject的“观察权”,首先需要向Subject 申请注册,如果惹Subject生气了,不让你观察了,就把你踢开。Subject一旦发生了变化,就立刻通知所有观察者,引起观察者的更新

黑体字就是Subject接口中的三个和Observer接口中的一个关键的抽象方法,必须实现:
申请注册:registerObserver()
踢开       :removeObserver()
通知       :notifyObservers()
更新       :update()

值得注意的是:update()方法传递的参数,可以传递整个subject对象,也可以只传递部分有用的数据成员。实验楼网站课程中的例子就是传递整个subject对象,《Head First Design Pattern》就是传递部分有用的数据成员。无论无何,最关键的是:
Subject对象中的数据成员发生改变
触发Subject.notifyObservers()方法
触发所有Observer.update() 方法。
万变离不开这个链条。

Java中有一个java.util.Observable类(被观察者,Subject);还有一个java.util.Observer接口(观察者,Obserer)。看来观察者模式很常用,以至于都写进到java类库里面去了。

更多设计模式,在新标签页中打开这里

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章