设计模式之观察者模式

设计模式之观察者模式

1. 什么是观察者模式

Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。

Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。

在这里插入图片描述

  • Subject(被观察者)
    被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。

  • ConcreteSubject
    被观察者的具体实现。包含一些基本的属性状态及其他操作。

  • Observer(观察者)
    接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。

  • ConcreteObserver
    观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。

2. 具体实例

首先我有一个Internet的气象站项目:

提供温度、气压和湿度的接口
测量数据更新时需时时通知给第三方
需要设计开放型API,便于其他第三方公司也能接入气象站获取数据

我首先按照面向对象的设计过程,我首先想到的是设计两个类,一个是天气的数据,一个就是公告板也就是对天气的数据进行操作的类

在这里插入图片描述

具体实现如下:

CurrentConditions:

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+"***");
    }
}

WeatherData:

public class WeatherData {
    private float mTemperature;
    private float mPressure;
    private float mHumidity;
    private CurrentConditions currentConditions;

    public WeatherData( CurrentConditions currentConditions){
        this.currentConditions = currentConditions;
    }
    public float getmTemperature() {
        return mTemperature;
    }
    public float getmPressure() {
        return mPressure;
    }
    public float getmHumidity() {
        return mHumidity;
    }

    public void dataChange(){
        currentConditions.update( getmTemperature(),getmPressure(),getmHumidity());
    }

    public void setData(float mTemperature,float mPressure,float mHumidity)
    {
        this.mTemperature=mTemperature;
        this.mPressure=mPressure;
        this.mHumidity=mHumidity;
        dataChange();
    }
}

这样设计带来的问题是什么呢?

1)其他第三方公司接入气象站获取数据的问题
2)无法在运行时动态的添加第三方

也就是说我们想要再添加新的公告板的时候,同时需要更改WeatherData类,这样的话工作量变大,不符合设计要求。

根据上面观察者模式,我们重新设计我们的方案,也就是留出subject和observer两个接口,由WeatherDada和CurrentConditions分别继承实现,这样的话我再来新的公告板的话只需要扩展observer这个接口就可以了。

在这里插入图片描述

observer接口:

public interface Observer {
    public void update(float mTemperatrue,float mPressure,float mHumidity);
}

subject接口:

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

}

WeatherDataSt继承自subject,然后observer由ArrayList组成,这样的话每扩展一个公告板就只需要注册Observer就可以了。

public class WeatherDataSt implements Subject {
    private float mTemperature;
    private float mPressure;
    private float mHumidityp;
    ArrayList<Observer> observers;

    public float getmTemperature() {
        return mTemperature;
    }

    public float getmPressure() {
        return mPressure;
    }

    public float getmHumidityp() {
        return mHumidityp;
    }
    
    public WeatherDataSt(){
        observers = new ArrayList<>();
    }

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

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

    }

    @Override
    public void notifyObservers() {
        for (int i = 0; i < observers.size(); i++){
            observers.get(i).update(getmTemperature(),getmPressure(),getmHumidityp());
        }
    }

    public void dataChange(){
       notifyObservers();
    }

    public void setData(float mTemperature,float mPressure,float mHumidity){
        this.mTemperature = mTemperature;
        this.mPressure = mPressure;
        this.mHumidityp = mHumidity;
        dataChange();
    }
}

公告板

public class ConcurrentConditions implements Observer{

    private float mTemperature;
    private float mPressure;
    private float mHumidityp;

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

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

这个时候我想要添加一个气象预报的公告板,只需要继承Observer接口然后在WeatherData中注册就可以了

public class ForcastConditions implements Observer{
    private float mTemperature;
    private float mPressure;
    private float mHumidityp;
    @Override
    public void update(float mTemperature, float mPressure, float mHumidity) {
        this.mTemperature = mTemperature;
        this.mPressure = mPressure;
        this.mHumidityp = mHumidity;
        displsy();
    }

    public void displsy(){
        System.out.println("**明天温度:"+(mTemperature+Math.random())+"**");
        System.out.println("**明天气压:"+(mPressure+10*Math.random())+"**");
        System.out.println("**明天湿度:"+(mHumidityp+Math.random())+"**");
    }
}
public class InternetWeatherOb {

    public static void main(String[] args){
        ConcurrentConditions concurrentConditions = new ConcurrentConditions();
        WeatherDataSt weatherDataSt = new WeatherDataSt();
        weatherDataSt.registerObserver(concurrentConditions);
        weatherDataSt.setData(10,200,20);

        ForcastConditions forcastConditions = new ForcastConditions();
        weatherDataSt.registerObserver(forcastConditions);
        weatherDataSt.setData(20,300,30);
    }
}

通过上面的例子我们可以看出通过观察者模式,我们可以轻松的扩展程序,扩展后只需要让观察者通知被观察者发生的改变即可。

3. java内置的观察者模式

Java内置的观察者:

  • Observable
  • Observer

接下来通过内置的观察者模式来上面的例子

public class WeatherData extends Observable{
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;

    public float getTemperature()
    {
        return mTemperatrue;
    }

    public float getPressure()
    {
        return mPressure;
    }

    public float getHumidity()
    {
        return mHumidity;
    }
    public void dataChange(){
        this.setChanged(); //boolean类型的,是否发生了改变
        this.notifyObservers(new Data(getTemperature(),getPressure(),getHumidity()));    //通知观察者发生的改变
    }

    public void setData(float mTemperatrue,float mPressure,float mHumidity)
    {
        this.mTemperatrue=mTemperatrue;
        this.mPressure=mPressure;
        this.mHumidity=mHumidity;
        dataChange();
    }

    public class Data
    {
        public float mTemperatrue;
        public float mPressure;
        public float mHumidity;
        public Data(float mTemperatrue,float mPressure,float mHumidity)
        {
            this.mTemperatrue=mTemperatrue;
            this.mPressure=mPressure;
            this.mHumidity=mHumidity;
        }
    }
}
public class ConcurrentConditions implements Observer {

    private float mTemperature;
    private float mPressure;
    private float mHumidityp;

    @Override
    public void update(Observable o, Object arg) {
        this.mTemperature = ((WeatherData.Data) arg).mTemperatrue;
        this.mPressure = ((WeatherData.Data) arg).mPressure;
        this.mHumidityp = ((WeatherData.Data) arg).mHumidity;
        display();
    }
    public void display()
    {
        System.out.println("***Today mTemperatrue:" +mTemperature+"***");
        System.out.println("***Today mPressure:" +mPressure+"***");
        System.out.println("***Today mHumidity:" +mHumidityp+"***");
    }
}
public class InternetWeather {
    public static void main(String[] args){
        ConcurrentConditions concurrentConditions = new ConcurrentConditions();
        WeatherData weatherData = new WeatherData();
        weatherData.addObserver(concurrentConditions);    //添加
        weatherData.setData(10,100,10);
    }
}

其实就是通过继承Java内部的Observable和Observer,实现观察者模式,不用自己去写这俩个接口了。

4. 典型应用

Observer模式的典型应用:

  • 侦听事件驱动程序设计中的外部事件

  • 侦听/监视某个对象的状态变化

  • 发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值