设计模式之观察者模式

上一篇:设计模式之策略模式
故事要从气象站说起,气象站有个WeatherData对象,这个对象负责拿到所有的气象数据(温度、湿度、气压),而气象站同时也存在好几个公告板,负责显示气象数据,并且要实时更新。
在这里插入图片描述
很快我们便设计了下面的类图:
在WeatherData类中放一个公布板(CurrentDisplay)属性,在每次数据更新的时候调用notify方法来通知公布版更新实时数据。
在这里插入图片描述
很快的就可以将我们的气象站设计出来,在WeatherData类中放入一个CurrentDisplay对象,每次更新数据就通知我们的公告板对象进行更新数据。

package shejimoshi.Observer;

public class WeatherData {

    private float teperature;
    private float hunidity;
    private float pressure;

    private CurrentDisplay display;

    WeatherData(CurrentDisplay display){
        this.display = display;
    }

    public void notifyDisplay(){
        this.display.update(teperature,hunidity,pressure);
    }

    public float getTeperature() {
        return teperature;
    }

    public void setTeperature(float teperature) {
        this.teperature = teperature;
    }

    public float getHunidity() {
        return hunidity;
    }

    public void setHunidity(float hunidity) {
        this.hunidity = hunidity;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }
}



package shejimoshi.Observer;

public class CurrentDisplay {

    private float teperature;
    private float hunidity;
    private float pressure;

    public void update(float teperature,float hunidity,float pressure){
        this.teperature = teperature;
        this.hunidity = hunidity;
        this.pressure = pressure;
        display();
    }

    public void display(){
        System.out.println("Current conditions:"+teperature+"and "+hunidity+"%humidity");
    }

    public static void main(String[] args) {
        CurrentDisplay display = new CurrentDisplay();
        WeatherData data = new WeatherData(display);
        data.setTeperature(30);
        data.setHunidity(1.1f);
        data.setPressure(1.3f);
        data.notifyDisplay();
    }
}

系统如期上线,刚开始没问题,可是过了一段时间,气象站增加了一个公告板(SecondDisplay)用来显示一些基于观测值(温度,湿度,气压…)的一些计算结果。
这个时候我们就会在我们的WeatherData中在加一个属性SecondDisplay,然后来了几十个显示板,类爆炸了,WeatherData被我们修改的千疮百孔,如果有一天气象站突然不用某个显示板了,又要去修改,完了。
这就违反了设计模式的原则:开闭原则
开闭原则:使软件中的对象对扩展开放,对修改关闭

观察者模式

既然需要很多个显示板,那么观察者模式就在WeatherData中存放一个容器用来存放显示板(Display),然后各个显示板就实现Display接口,再来一个显示板的时候就直接将显示板加入到WeatherData中的容器中,很快就能实现下面的代码:

package shejimoshi.Observer;
//显示板接口
public interface Display {
    public void update(float teperature,float hunidity,float pressure);
}

package shejimoshi.Observer;
//主题接口也就是WeatherData实现的接口
public interface Subjcet {
    public void registerDisplay(Display d);
    public void removeDisplay(Display d);
    public void notifyDisplay();
}
package shejimoshi.Observer;

public class CurrentDisplay implements Display{

    private float teperature;
    private float hunidity;
    private float pressure;

    public void update(float teperature,float hunidity,float pressure){
        this.teperature = teperature;
        this.hunidity = hunidity;
        this.pressure = pressure;
        display();
    }

    public void display(){
        System.out.println("Current conditions:"+teperature+"and "+hunidity+"%humidity");
    }

}
package shejimoshi.Observer;

import java.util.ArrayList;

public class WeatherData implements Subjcet{

    private float teperature;
    private float hunidity;
    private float pressure;

    private ArrayList displays;

    private CurrentDisplay display;

    WeatherData(){
        displays = new ArrayList();
    }

    @Override
    public void registerDisplay(Display d) {
        displays.add(d);
    }

    @Override
    public void removeDisplay(Display d) {
        int i = displays.indexOf(d);
        if(i>=0){
            displays.remove(i);
        }
    }

    public void notifyDisplay(){
        for (Object o:displays) {
            Display display = (Display)o;
            display.update(teperature,hunidity,pressure);
        }
    }

    public float getTeperature() {
        return teperature;
    }

    public void setTeperature(float teperature) {
        this.teperature = teperature;
    }

    public float getHunidity() {
        return hunidity;
    }

    public void setHunidity(float hunidity) {
        this.hunidity = hunidity;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }


    public static void main(String[] args) {
        CurrentDisplay display = new CurrentDisplay();
        WeatherData data = new WeatherData();
        data.registerDisplay(display);
        data.setTeperature(30);
        data.setHunidity(1.1f);
        data.setPressure(1.3f);
        data.notifyDisplay();
    }
}

这样每来一个显示板就可以将显示板注册到我们的主题(WeatherData)中去,再主题更新数据就会通知显示板来更新数据,如果不需要某个显示板就直接remove掉,很灵活。

推、拉

系统如期上线,顺利运行,突然有一天,一个显示板不高兴了:每次你主题更新的时候都要通知我(),我显得很被动,我需要是,我每次需要数据的时候我自己去拿数据,并且,我如果要不订阅你(remove掉),我需要通知你WeatherData,然后才能remove,我需要的是自己注册与否是我自己来决定,就像订报纸一样,我不订阅了我自己直接取消就好了:

package shejimoshi.Observer;

public class CurrentDisplay implements Display{

    private float teperature;
    private float hunidity;
    private float pressure;

    private Subjcet subjcet;

    CurrentDisplay(Subjcet subjcet){
        this.subjcet = subjcet;
    }

    public void regist(){
        subjcet.registerDisplay(this);
    }

    public void remove(){
        subjcet.removeDisplay(this);
    }

    public void getData(){
        subjcet.notifyDisplay();
    }

    public void update(float teperature,float hunidity,float pressure){
        this.teperature = teperature;
        this.hunidity = hunidity;
        this.pressure = pressure;
        display();
    }

    public void display(){
        System.out.println("Current conditions:"+teperature+"and "+hunidity+"%humidity");
    }

}

这样在Display中放入一个WeatherData之后,每个显示板自己就可以决定什么时候需要拿数据(),以及自己决定自己是否订阅这个Subjcet。

最后

在jdk中的观察者模式是这样的:
Observer是个接口,Observable是个类,因为是类,所以不可以在继承Observable的时候再去继承别的类的特性,所以这就有很大的局限性,这边就不具体展开说了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小丸子呢

致力于源码分析,期待您的激励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值