23种设计模式之观察者模式

观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化

1、Internet气象站项目

提供温度、气压和湿度接口

测量数据更新时需要通知给第三方

需要设计开放型API,便于其他第三方公司也能接入气象站获取数据

普通实现如下:

2、WeatherData类

测量数据更新时会调用类中的dataChange方法,dataChange方法中通过getTemperature、getPressure、getHumidity方法获得最新数据

 

public class WeatherData {

    private float mTemperature;//温度
    private float mPreesure;//气压
    private float mHumidity;//湿度

    private CurrentConditions mCurrentConditions;

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

    public float getTemperature() {
        return mTemperature;
    }

    public float getPreesure() {
        return mPreesure;
    }

    public float getHumidity() {
        return mHumidity;
    }

    //气象站数据变动后会调用该方法
    public void dataChange() {
        mCurrentConditions.update(getTemperature(), getPreesure(), getHumidity());
    }

    //模拟气象站数据变化,要调用dataChange方法
    public void setData(float mTemperature, float mPreesure, float mHumidity) {
        this.mTemperature = mTemperature;
        this.mPreesure = mPreesure;
        this.mHumidity = mHumidity;
        dataChange();
    }

}
WeatherData

 3、CurrentConditions类

某公司想接入气象站,展示气象数据,气象数据更新时,会调用CurrentConditions类的update方法来更新展示的气象数据

public class CurrentConditions {

    private float mTemperature;
    private float mPressure;
    private float mHumidity;

    public void update(float mTemperature, float mPressure, float mHumidity) {
        this.mTemperature = mTemperature;
        this.mPressure = mPressure;
        this.mHumidity = mHumidity;
        //假如更新后直接显示(也可以后期通过某条件后调用)
        display();
    }

    public void display() {
        System.out.println("***Today mTemperature: " + mTemperature + "***");
        System.out.println("***Today mPressure: " + mPressure + "***");
        System.out.println("***Today mHumidity: " + mHumidity + "***");
    }

}
CurrentConditions

4、InternetWeather类

气象站注册应用类,启动后,通过setData模拟气象数据变化

public class InternetWeather {

    public static void main(String[] args) {
        CurrentConditions currentConditions;
        WeatherData weatherData;

        currentConditions = new CurrentConditions();
        weatherData = new WeatherData(currentConditions);
        weatherData.setData(30, 150, 40);
    }

}
InternetWeather

5、引发的问题,如果再有其他公司想接入气象站,那么还要在WeatherData类中添加另一个公司的CurrentConditions类,同时还要停掉气象站服务,重新编译WeatherData类

同样如果有公司不想接入气象站了,那么还要去除对应类对象,停服务重新编译

6、使用观察者模式来解决此类问题,想接入气象站就去注册登记,不想接入就注册取消,登记的公司在气象数据变化后都会收到通知

代码实现:

public interface Subject {

    void registerObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObservers();

}
Subject 接口
public interface Observer {

    void update(float mTemperature,float mPressure,float mHumidity);

}
Observer 接口
public class CurrentConditions implements Observer {

    private float mTemperature;
    private float mPressure;
    private float mHumidity;

    public void update(float mTemperature, float mPressure, float mHumidity) {
        this.mTemperature = mTemperature;
        this.mPressure = mPressure;
        this.mHumidity = mHumidity;
        display();
    }

    public void display(){
        System.out.println("***Today mTemperature: " + mTemperature + "***");
        System.out.println("***Today mPressure: " + mPressure + "***");
        System.out.println("***Today mHumidity: " + mHumidity + "***");
    }
}
CurrentConditions implements Observer
public class ForcastConditions implements Observer {

    private float mTemperature;
    private float mPressure;
    private float mHumidity;

    public void update(float mTemperature, float mPressure, float mHumidity) {
        this.mTemperature = mTemperature;
        this.mPressure = mPressure;
        this.mHumidity = mHumidity;
        display();
    }

    public void display(){
        System.out.println("***Tomorrow mTemperature: " + mTemperature + "***");
        System.out.println("***Tomorrow mPressure: " + mPressure + "***");
        System.out.println("***Tomorrow mHumidity: " + mHumidity + "***");
    }
}
ForcastConditions implements Observer
public class WeatherData implements Subject {

    private float mTemperature;//温度
    private float mPreesure;//气压
    private float mHumidity;//湿度
    private List<Observer> mObservers;

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

    public float getmTemperature() {
        return mTemperature;
    }

    public void setmTemperature(float mTemperature) {
        this.mTemperature = mTemperature;
    }

    public float getmPreesure() {
        return mPreesure;
    }

    public void setmPreesure(float mPreesure) {
        this.mPreesure = mPreesure;
    }

    public float getmHumidity() {
        return mHumidity;
    }

    public void setmHumidity(float mHumidity) {
        this.mHumidity = mHumidity;
    }

    //气象站数据变动后会调用该方法
    public void dataChange() {
        notifyObservers();
    }

    //模拟气象站数据变化,要调用dataChange方法
    public void setData(float mTemperature, float mPreesure, float mHumidity) {
        this.mTemperature = mTemperature;
        this.mPreesure = mPreesure;
        this.mHumidity = mHumidity;
        dataChange();
    }

    public void registerObserver(Observer observer) {
        mObservers.add(observer);
    }

    public void removeObserver(Observer observer) {
        if (mObservers.contains(observer))
            mObservers.remove(observer);
    }

    public void notifyObservers() {
        for (int i = 0; i < mObservers.size(); i++) {
            mObservers.get(i).update(getmTemperature(), getmPreesure(), getmHumidity());
        }
    }
}
WeatherData implements Subject
public class InternetWeather {

    public static void main(String[] args) {

        CurrentConditions currentConditions;
        ForcastConditions forcastConditions;
        WeatherData weatherData;

        currentConditions = new CurrentConditions();
        forcastConditions = new ForcastConditions();
        weatherData = new WeatherData();

        weatherData.registerObserver(currentConditions);
        weatherData.registerObserver(forcastConditions);

        weatherData.setData(30, 150, 40);
        System.out.println("````````````````````");
        weatherData.removeObserver(forcastConditions);
        weatherData.setData(40,160,50);


    }

}
注册服务应用InternetWeather

7、Java内置观察者(允许发出通知时直接推送给观察者,也可以通知观察者后让观察者来拉取数据)

Java内置观察者使用的是Observable类(不是接口,作用类似实现Subject接口的类),和Observer接口

注意,在观察者通知被观察者前要调用setChange方法

public class CurrentConditions implements Observer {

    private float mTemperature;
    private float mPressure;
    private float mHumidity;

    public void update(Observable o, Object arg) {
        this.mTemperature=((Data)arg).mTemperature;
        this.mPressure=((Data)arg).mPressure;
        this.mHumidity=((Data)arg).mHumidity;
        display();
    }

    public void display(){
        System.out.println("***Today mTemperature: " + mTemperature + "***");
        System.out.println("***Today mPressure: " + mPressure + "***");
        System.out.println("***Today mHumidity: " + mHumidity + "***");
    }
}
Java内置观察者CurrentConditions implements Observer
public class ForcastConditions implements Observer {

    private float mTemperature;
    private float mPressure;
    private float mHumidity;

    public void update(Observable o, Object arg) {
        this.mTemperature=((WeatherData.Data)arg).mTemperature;
        this.mPressure=((WeatherData.Data)arg).mPressure;
        this.mHumidity=((WeatherData.Data)arg).mHumidity;
        display();
    }

    public void display(){
        System.out.println("***Tomorrow mTemperature: " + mTemperature+1 + "***");
        System.out.println("***Tomorrow mPressure: " + mPressure+1 + "***");
        System.out.println("***Tomorrow mHumidity: " + mHumidity+1 + "***");
    }
}
Java内置观察者ForcastConditions implements Observer
public class WeatherData extends Observable {

    private float mTemperature;//温度
    private float mPressure;//气压
    private float mHumidity;//湿度

    public float getmTemperature() {
        return mTemperature;
    }

    public void setmTemperature(float mTemperature) {
        this.mTemperature = mTemperature;
    }

    public float getmPreesure() {
        return mPressure;
    }

    public void setmPreesure(float mPreesure) {
        this.mPressure = mPreesure;
    }

    public float getmHumidity() {
        return mHumidity;
    }

    public void setmHumidity(float mHumidity) {
        this.mHumidity = mHumidity;
    }

    //气象站数据变动后会调用该方法
    public void dataChange() {
        this.setChanged();//一定要先调用这个方法,此方法是灵活设置是否通知观察者(如数据变化不大时不需要通知)
//        this.notifyObservers();//通知观察者,来拉取数据
        this.notifyObservers(new Data(getmTemperature(),getmPreesure(),getmHumidity()));
    }

    //模拟气象站数据变化,要调用dataChange方法
    public void setData(float mTemperature, float mPressure, float mHumidity) {
        this.mTemperature = mTemperature;
        this.mPressure = mPressure;
        this.mHumidity = mHumidity;
        dataChange();
    }

    public class Data {

        public float mTemperature;//温度
        public float mPressure;//气压
        public float mHumidity;//湿度

        public Data(float mTemperature, float mPrsesure, float mHumidity) {
            this.mTemperature = mTemperature;
            this.mPressure = mPressure;
            this.mHumidity = mHumidity;
        }
    }
}
Java内置观察者WeatherData extends Observable
public class InternetWeather {

    public static void main(String[] args) {

        CurrentConditions currentConditions;
        ForcastConditions forcastConditions;
        WeatherData weatherData;

        currentConditions = new CurrentConditions();
        forcastConditions = new ForcastConditions();
        weatherData = new WeatherData();

        //注意注册顺序,最后注册的先通知
        weatherData.addObserver(currentConditions);
        weatherData.addObserver(forcastConditions);

        weatherData.setData(30, 150, 40);

        System.out.println("````````````````````");
        weatherData.deleteObserver(forcastConditions);
        weatherData.setData(40,160,50);


    }

}
Java内置观察者WeatherData extends Observable
原文地址:https://www.cnblogs.com/hujiapeng/p/7899715.html