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

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

tags: 设计模式

本章主要介绍观察者模式。观察者模式可以帮助对象知悉现况,不会错过对象感兴趣的事。对象甚至在运行时可决定是否要继续被通知。观察者模式是JDK中使用最多的模式之一。本章也会一并介绍一对多关系,以及松耦合。有了观察者,消息会更灵通。

1. 认识观察者模式

出版者+订阅者=观察者模式

观察者模式类似于报纸的订阅,只是名称不太一样:出版者改称为"主题"(Subject),订阅者改称为"观察者"(Observer)。

主题对象:主题对象管理某些数据

观察者对象:观察者订阅(注册)主题以便在主题数据改变时能够收到更新

当主题内的数据发生改变时,新的数据就会以某种形式送到观察者手上


2. 定义观察者模式

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

实现观察者模式的方法不止一种,但是以包含Subject与Observer接口的类设计的做法最常见。


3. OO设计原则

为了交互对象之间的松耦合设计而努力


4. 松耦合

观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

当两个对象之间松耦合,它们依然可以交互,但是不必清楚彼此的细节。

松耦合的设计能建立有弹性的OO系统,因为对象之间的互相依赖降到了最低。


5. Java内置的观察者模式

5.1 Observer接口和Observable类

Java API有内置的观察者模式。java.util包中包含最基本的Observer接口和Observable类,Observer接口和Observable类使用上更加方便,因为许多功能都已经事先实现过了。通过使用推(push)或拉(pull)的方式传送数据。

由于Java内置的支持,只需扩展(继承)Observable,并告诉它核实该通知观察者,剩下的事API会帮助你完成。

Observable类中的方法有:

  • addObserver()
  • deleteObserver()
  • notifyObserver()
  • setChanged()

Observable是一个"类",而非接口。Observable类会追踪所有的观察者,并通知它们。之前的"主题"(Subject),也称为"可观察者"(Observable)继承自Observable类。在继承的类(主题)中不需要再提供register()、remove()和notifyObservers()方法,因为已经从超类(Observable)中继承了。

5.2 Java内置的观察者模式

5.2.1 Java内置观察者模式与观察者模式的差别

主题扩展自Observable类,并继承了增加、删除、通知观察者的方法以及其他方法。

5.2.2 Java内置观察者模式的使用
  • 将对象变成观察者:实现观察者接口(java.util.Observer),然后调用任何Observable对象的addObserver()方法。当不想再当观察者时,调用deleteObserver()方法即可。

  • 可观察者(主题)传送数据

    • 利用扩展java.util.Observable类产生"可观察者"

    • 调用setChanged()方法,标记状态已经改变

    • 调用notifyObservers()或notifyObservers(Object arg)

      如果想"推"(push)数据给观察者,就把数据当做数据对象传送给notifyObservers(Object arg)方法。否则,观察者就必须从可观察者对象中"拉"(pull)数据。

  • 观察者接受数据:观察者实现更新的方法

    update(Observable o,Object arg)
    //Observable o:主题(可观察者)本身当做第一个变量,使观察者知道是哪一个主题通知它的
    //Object arg:传入notifyObservers()的数据对象。未说明则为空。
    
5.2.3 setChanged()方法

setChanged()方法用来标记已经改变的事实,让notifyObservers()方法知道当它被调用时应该更新观察者。如果调用notifyObservers()之前未调用setChanged()方法,则观察者就"不会"被通知。

setChanged()方法的伪代码:

setChanged(){
    changed = true     //setChanged()方法把changed标志设为true
}
//推数据
notifyObservers(Object arg){         
    //notifyObservers()方法只会在changed标为"true"时通知观察者
    if(changed){
        for every observer on the list{
            call update(this,arg)
        }
        changed = false
        //通知观察者之后,把changed标志设回false
        //所以若未调用setChanged()方法,则changed默认为false,就不会通知观察者进行更新
    }
}
//拉数据
notifyObservers(){
    notifyObservers(null)
}
//clearChanged():将changed状态设置回false
//hasChanged():得到changed标志当前的状态值(true or false)

5.3 Java内置观察者模式的使用步骤

  1. 导入正确的Observable/Observer

    import java.util.Observer;
    import java.util.Observavle;
    
  2. 继承Observable类

    public class Xxx extends Observable{
        //代码
    }
    
  3. 调用setChanged()方法和notifyObservers()方法

    public void xxx(){
        setChanged();          //注意调用先后顺序,setChanged()在前,notifyObservers()在后 
        notifyObservers();     //notifyObservers(Object args);
    }
    

5.4 Java内置观察者模式的缺点

  • Observable是一个类,限制了Observable的复用潜力

    1. 因为Observable是一个类,所以必须设计一个类继承它。如果某类想同时具有Observable类和另一个超类的行为,就会陷入两难,毕竟Java不支持多重继承。
    2. 因为没有Observable接口,所以无法建立自己的实现,和Java内置的Observers API搭配使用,也无法将java.util的实现换成另一套做法的实现。
  • Observable将关键的方法保护起来了

    在Observable API中,setChanged()方法被定义成protected。这意味着:除非继承自Observable,否则无法创建Observable实例并组合到自己的对象中。该设计违反了"多用组合,少用继承"这个设计原则。


6. 观察者模式如何遵循设计原则

6.1 设计原则:找出程序中会变化的部分,将其和固定不变的部分相分离

**在观察者模式中,会变化的是主题的状态,以及观察者的数目和类型。**使用此模式,可以改变依赖于主题状态的对象,而不必改变主题。

6.2 设计模式:针对接口编程,不针对实现编程

主题与观察者都使用接口:观察者利用主题的接口向主题注册,主题利用观察者接口通知观察者。这样既可以让两者之间正常运作,又同时具有松耦合的优点。

6.3 设计模式:多用组合,少用继承

观察者模式利用"组合"将许多观察者组合进主题中。对象之间的关系并非通过继承产生,而是在运行时利用组合的方式产生的。


7. 要点小结

  • 观察者模式定义了对象之间一对多的关系
  • 主题(可观察者)用一个共同的接口来更新观察者
  • 观察者和主题(可观察者)之间用松耦合方式(loosecoupling)结合,可观察者不知道观察者的细节,只知道观察者实现了观察者接口
  • 使用观察者模式时,既可从被观察者处推(push)数据,也可从被观察者处拉(pull)数据(推的方式更安全)
  • 有多个观察者时,不可以依赖特定的通知次序
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值