Head First- 观察者模式(Obserber Pattern)

本文介绍了观察者模式的基本概念和应用场景,详细解释了如何通过定义对象间的一对多依赖关系实现数据更新。并通过一个气象监测系统的实例,展示了如何利用观察者模式进行设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 观察者模式(Obserber Pattern):定义对象之间一对多的依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

    观察者模式主要用来处理一对多的数据更新和传输的关系。易于对实现对象的控制和更新。观察者模式主要分为两部分,一部分称为主题(Subject)类似于报纸的出版商,另一部分称为观察者(Observer)类似于报纸的订购者。这个模式就相当于出版商和订购者的关系,当订购者需要得到数据时就会在出版商这里注册,以通知出版商,取得获取数据的资格,一旦有数据更新的时候订购者就像读报纸一样得到数据,这样报社不需要去照顾订购者的数量和实现方法。只需要对已注册的跟新即可。

    举个例子

    接到一个项目,用来做气象监测,分为两个部分,一个是WeatherData对象:追踪监测的气象数据,并跟新布告板。另一个是布告板:通过终端(手机、电视、电脑)显示当前天气状况给用户。

    分析需求:

      已知:1WeatherData类有三个get方法,取得三个测量值:温度、湿度和气压。

            2)有一个update方法。

            3)一旦WeatherData有新的数据产生时,就会立即向布告板更新。

            4)需要可扩展,因为终端不同,需要能让其他开发人员建立布告板。

    这样就可以来设计了,通过上面对观察者的介绍和针对接口的OO原则。

       定义主题接口:

//主题接口
public interface Subject{
    //注册观察者方法
    public void registerObserver(Observer ob);
    //删除观察者方法
    public void removeObserver(Observer ob);
    //通知观察者方法
    public void notifyObserver(Observer ob);
}

观察者接口:

//观察者接口
public interface Observer{
    //
更新数据方法
    public void update(float temp,float humidity,float pressure);
}

发布接口:

//发布接口
public interface DisplayElement{
    public void display();
}

 

开始实现:

         首先实现WeatherData
//通过Subject接口实现WeatherData
public class WeatherData implements Subject{
    //定义一个列表,用来盛放注册的观察者
    private ArrayList observers;
 
    private float temperature;
    private float humidity;
    private float pressure;
 
    public WeatherData(){
        observers=new ArrayList();
    }
 
    public void registerObserver(Observer ob){
        observers.add(ob);
    }
    public void removeObserver(Observer ob){
        //返回此列表中首次出现的ob的索引,如果此列表不包含元素,则返回 -1。
        if(observers.indexOf(ob)>=0)
            observers.remove(ob);
    }
    public void notifyObserver(Observer ob){
        for(int i=0;i<observers.size();i++){
            Observer observer=(Observer)    observers.get(i);
            observer.update(temperature,humidity,pressure);
        }
    }
    //当WeatherData数据改变时,才会更新。
    public void measurementsChanged(){
        notifyObserver();
    }

    public void setMeasurements(float temperature,float humidity,float pressure){
        this.temperature=temperature;
        this.humidity=humidity;
        this.pressure=pressure;
 
        measurementsChanged();
    }
}
}

通过Observer实现布告板:

//通过Observer接口实布告板
public class BillBoard implements Observer,DisplayElement(){
    private float temperature;
    private float humidity;
    private float pressure;
 
    public BillBoard(Subject WeatherData){
        this.WeatherData=WeatherData;
        WeatherData.removeObserver(this);
    }
    public void update(float temperature,float humidity,float pressure){
        this.temperature=temperature;
        this.humidity=humidity;
        this.pressure=pressure;
 
        display();
    }


    /*
        
这个方法由开发人员重写
    */

    @Override
    public void display(){
    }
 
}

这样整个设计基本上就OK了,下面写个test类来测试一下:

//测试类
public class test{
    public static void main(String args[]){
        WeatherData watherData=new WeatherData();
 
        BillBoard billBoard=new BillBoard();

//不止这一个公告板,如果有的话在下面继续加
 
        weatherData.setMeasurements(22,55,66);
        weatherData.setMeasurements(5,96,47);
    }
 
}

    不出错的话这个任务基本上就完成了。

到目前为止,已经从无到有的完成了Observer Pattern。关于观察者,主题只知道观察者实现的Observer接口,不需要知道其他的任何细节。  任何时候都可以增加新的观察者,只需要在主题ArrayList里面注册就可以。   有新的类型观察者出现时,主题代码还是不需要修改,主题代码不在乎别的,只有一个功能就是给已注册的观察者发送数据。   独立的复用主题或者观察者,二者独立,只需要遵守接口,改变不会产生影响。

    多说一点,上面的这种设计实际上是由主题进行一个类似于“推”的动作,它把数据推送到各个观察者。观察者是被动接收数据的对象。实际上Java有一个内置的观察者模式,实现的是另一种不同的思路。说白了是“拉”,观察者从主题里去拉取自己需要的数据,去按照自己的需求主动获取数据。位于java.util包里。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值