Head First 设计模式-观察者模式

定义:在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
有时又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
类图:
这里写图片描述
角色:
•Subject:抽象主题(抽象被观察者),定义为一个接口,抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供增加、删除、通知观察者的方法。
•ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
它就是一对多里那个“一”。
•Observer:抽象观察者,提供一个接口,接口定义了一个多态更新接口,使得在得到主题更改通知时更新自己。
•ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。


现在来进行一个小需求实现
:建立一个Internet气象观测站,由WeatherData对象负责追踪天气状况,温度、湿度、气压,建立三个布告板,分别显示目前状况、气象统计、简单的预报。
类图:

这里写图片描述
也就是说WeatherData对象要及时通知Observer和DisplayElement接口那四个实现类的布告板天气变化,刚好是一对多的关系,WeatherData属性值变化及时通知所有布告板,典型观察者模式。
1.下面我们先写接口

interface Subject{//主题接口 封装注册、删除、通知观察者方法
    public void registerObservers(Observer o);
    public void removeObservers(Observer o);
    public void notifyObservers();
}
interface Observer{//观察者接口 提供更新的多态方法,不同的具体观察者也就是布告板重写实现自己的更新,具体是更新温度、湿度、还是气压
    public void update(float temp,float humidity,float pressure);//更新观察者值得入口
}
interface DisplayElement{//布告板接口 为了以后用户新增自己的布告板使用
    public void display();//具体布告板重写展示方法,决定要显示啥
}

2.现在来写WeatherData类

class WeatherData implements Subject{
    private ArrayList observers;//用来存放多个观察者
    private float temperature;
    private float humidity;
    private float pressure;
    public WeatherData(){//构造函数
        observers = new ArrayList();//给observers分配空间
    }
    public void registerObservers(Observer o){//重写观察者注册方法
        observers.add(o);//注册就是把观察者加到队列里
    }
    public void removeObservers(Observer o){//重写移除观察者方法
        int i = observers.indexOf(o);//拿到要删除观察者的位置
        if(i>= 0){
            observers.remove(i);
        }
    }
    public void notifyObservers(){//通知所有观察者
        for(int i=0;i<observers.size();i++){
            Observer observer = (Observer)observers.get(i);//获取所有队列里的观察者向上转型,向上转型就是只调父类对象的方法,但是真正执行的是子类重写的同名update方法,达到多态效果,就是不同布告板自己更新自己的
            observer.update(temperature, humidity, pressure);
        }
    }

    public void setMeasureMent(float temp,float humidity,float pressure){//把从气象站获取的天气数据赋给自己的属性
        temperature = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementChanged();//通知数据改变了
    }
    public void measurementChanged(){
        notifyObservers();//数据改变了去通知所有观察者
    }
}

3.写具体的布告板实现类
我就写了俩,一个意思,嘻嘻。。

//当前情况布告板  实现Observerversion接口和DisplayElement接口,因为要用更新和显示方法
class CurrentConditionDisplay implements Observer,DisplayElement{
    private float temperature;//温度
    private float humidity;//湿度
    private Subject WeatherData;
    public CurrentConditionDisplay(Subject weather){//构造函数
        this.WeatherData = weather;
        WeatherData.registerObservers(this);//把当前对象注册到WeatherData属性队列里,就是说我注册了,请你有状态变化也通知我
    }
    public void update(float temp,float humidity,float pressure){//重写Observer类的更新
        this.temperature = temp;
        this.humidity = humidity;
        display();//更新完显示

    }
    public void display(){//重写DisplayElement的展示
        System.out.println("Current Condition: "+temperature+"F degrees and "+humidity+"% humidity");//就是把当前获取到的属性数据值展示出来
    }
}
//统计情况布告板  完全同上
class StatisticsConditionDisplay implements Observer,DisplayElement{
    private float temp;
    private float humid;
    private float pressure;
    private Subject weather;
    public StatisticsConditionDisplay(Subject sub){
        this.weather = sub;
        weather.registerObservers(this);
    }
    public void update(float temp,float humidity,float pressure){
        this.temp = temp ;
        this.humid = humidity;
        this.pressure = pressure;
            display();  
    }
    public void display(){
        System.out.println("Current Condition: "+temp+"F degrees and "+humid+"% humidity  "+pressure+" pressure");

    }
}

4.写个测试类

public class ObserverPattern {
    public static void main(String args[]){
        WeatherData data = new WeatherData();
        //new一个当前状况布告板加到观察者队列
        CurrentConditionDisplay current = new CurrentConditionDisplay(data);
        //new一个统计布告板加到观察者队列
        StatisticsConditionDisplay statistic = new StatisticsConditionDisplay(data);
        //WeatherData对象来设置当前气温变化值
        data.setMeasureMent(80, 60, 30.30f);
        data.setMeasureMent(33, 333, 33.33f);
        data.setMeasureMent(66, 666, 66.66f);
    }
}

5.显示结果
Current Condition: 80.0F degrees and 60.0% humidity
Current Condition: 80.0F degrees and 60.0% humidity 30.3 pressure
Current Condition: 33.0F degrees and 333.0% humidity
Current Condition: 33.0F degrees and 333.0% humidity 33.33 pressure
Current Condition: 66.0F degrees and 666.0% humidity
Current Condition: 66.0F degrees and 666.0% humidity 66.66 pressure


优点
观察者模式解除了主题和观察者的耦合,让耦合的双方都依赖于接口,而不依赖于具体的实现,是的各自的变化都不影响另一边,针对接口编程。
缺点
在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值