前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java设计模式之观察者模式

java设计模式之观察者模式

作者头像
BUG弄潮儿
发布2022-06-30 15:30:55
3180
发布2022-06-30 15:30:55
举报
文章被收录于专栏:JAVA乐园

观测者模式定义了对象之间的一对多依赖,当一个对象状态发生改变时,其依赖者便会收到通知并做相应的更新。其原则是:为交互对象之间松耦合。以松耦合方式在一系列对象之间沟通状态,我们可以独立复用主题(Subject)/可观测者(Observable)和观测者(Observer),即只要遵守接口规则改变其中一方并不会影响到另一方。这也是其主要的设计原则。下面是一个简单的气象站发送天气信息给布告板,然后布告板把天气信息显示在板上的例子。 首先先建立三个接口,主题(Subject)、观测者(Observer)和显示内容(DisplayElement),分别代表气象站、布告板信息接收和布告板信息显示。

代码语言:javascript
复制
/**
 *  主题
 */public interface Subject {
    // 观察者注册
    public void registerObserver(Observer o);    // 删除观察者
    public void removeObserver(Observer o);    // 当主题有内容更新时调用,用于通知观察者
    public void notifyObserver();
}
代码语言:javascript
复制
/**
 *  观察者
 */public interface Observer {
    // 当气象站观测的天气发生变化时,主题会把参数值传给观察者
    public void update(float temp);
}
代码语言:javascript
复制
/**
 *  用于布告板显示
 */public interface DisplayElement {
    // 在显示布告板上显示的操作
    public void display();
}

接下来是实现气象站()和布告板()了。

代码语言:javascript
复制
/**
 * 气象站实现主题,发布气象信息(气温)
 */public class WeatherStation implements Subject{
    private ArrayList observers;    private float temp;    public WeatherStation() {        // 加个ArrayList存放所有注册的Observer对象;
        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(i);
        }
    }    @Override
    public void notifyObserver() {        // 更新状态,调用Observer的update告诉观察者有新的信息
        for (int i = 0; i < observers.size(); i++) {
            Observer observer = (Observer) observers.get(i);
            observer.update(temp);
        }
    }    /*
     *  此方法用于气象站收到的数据,并且调用更新使数据实时通知给观察者
     */
    public void setMeasurements(float temp){        this.temp = temp;
        System.out.println("气象站测量的温度为:" + temp + "℃");
        notifyObserver();
    }
}
代码语言:javascript
复制
/**
 * 布告板上的状态显示
 */public class ConditionDisplay implements Observer,DisplayElement{
    private float temp;    private Subject weatherStation;    public ConditionDisplay(Subject weatherStation) {        // 构造时需要间主题/被观察者对象作为注册之用
        this.weatherStation = weatherStation;
        weatherStation.registerObserver(this);
    }    @Override
    public void display() {        // 将数据显示在布告板上
        System.out.println("布告板显示当前温度为:" + temp + "℃");
    }    @Override
    public void update(float temp) {        // 接受来自主题/被观察者(气象站)的数据
        this.temp = temp;
        display();
    }
}

测试结果

代码语言:javascript
复制
/**
 * 天气观测站
 */public class WeatherObserver {

    public static void main(String[] args) {        // 首先创建一个主题/被观察者
        WeatherStation weatherStation = new WeatherStation();        // 创建观察者并将被观察者对象传入
        ConditionDisplay conditionDisplay = new ConditionDisplay(weatherStation);        // 设置气象站模拟收到的气温数据
        weatherStation.setMeasurements(25);
        weatherStation.setMeasurements(24);
        weatherStation.setMeasurements(23);
    }
}

JAVA内置观察者模式 可以使用java内置的观察者模式,这样就无需自己写Subject和Observer类了,在java.util包下继承的Observable和实现Observer类即可。其修改后的代码如下:

代码语言:javascript
复制
/**
 * 继承java内置的被观察者,因此不再需要注册和删除了
 */public class WeatherStationN extends Observable{
    private float temperature;    public WeatherStationN() {        // 由于继承了Observable,它已经创建了一个Vector来存放Observer对象的容器,所以此处不用再建立ArrayList
    }    /*
     *  此方法用于气象站收到的数据,并且调用更新使数据实时通知给观察者
     */
    public void setMeasurements(float temp){        this.temperature = temp;
        System.out.println("气象站测量的温度为:" + temp + "℃");        // 更新强调用表示有状态更新
        setChanged();
        notifyObservers(temperature);
    }
}
代码语言:javascript
复制
/**
 * 实现java内置Observer接口
 */public class ConditionDisplayN implements java.util.Observer,DisplayElement{
    private Observable observable;    private float temp;    public ConditionDisplayN(Observable observable) {        // 构造器需要Observable作为参数
        this.observable = observable;
        observable.addObserver(this);
    }    @Override
    public void display() {        // 将数据显示在布告板上
        System.out.println("布告板显示当前温度为:" + temp + "℃");
    }    @Override
    public void update(Observable o, Object arg) {        // 当被观察者有更新使触发
        if (o instanceof WeatherStationN) {            this.temp = (float) arg;
            display();
        }
    }
}

测试运行结果

代码语言:javascript
复制
/**
 * 天气观测站
 */public class WeatherObserver {

    public static void main(String[] args) {        // 首先创建一个主题/被观察者
        WeatherStationN weatherStationN = new WeatherStationN();        // 创建观察者并将被观察者对象传入
        ConditionDisplayN conditionDisplayN = new ConditionDisplayN(weatherStationN);        // 设置气象站模拟收到的气温数据
        weatherStationN.setMeasurements(30);
        weatherStationN.setMeasurements(25);
        weatherStationN.setMeasurements(20);
    }
}

注意: Observer是一个接口,而Observable是一个类,在使用时必须继承它,因此在继承Observable时就无法再继承其他超类了,因为Java毕竟不支持多重继承。且在Observable更新前,即notifyObservers()或notifyObservers(Object arg)前要先调用setChange()标记更新状态

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BUG弄潮儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档