《C嵌入式编程设计模式》---读书笔记(3)

时间:2022-10-23 19:35:25

3.5 观察者模式

    观察者模式提供一种方法来使对象“监听”其他对象,而不需要修改任何数据服务器。这意味着传感器数据能够很容易地分享给其他元素,当编写传感器代理时,元素可能甚至还不存在。

3.5.1 抽象

    观察者模式(“发布-订阅模式”)通知一组感兴趣的客户相关数据已经改变。它不需要数据服务器对客户有任何先验信息,而客户仅提供订阅功能,允许客户在通知列表中动态添加(或删除)其本身。数据服务器可以执行各种通知策略,最常见的是当新数据到达时发送数据,同时客户也能定期更新。

3.5.2 问题

    在理想状态下,当数据已经改变时,每个客户都能够定期从数据服务器获取数据,但这造成计算浪费;而且客户通常不知道新数据何时可用,造成通信资源浪费。如果数据服务器推送数据,那么它必须知道其所有客户,打破常规客户机-服务器关系需要改变服务器,添加新的客户。

3.5.3 结构模式

    如下图所示,AbstractSubject添加维护感兴趣订阅者类列表机制的数据服务器。通过传递指向accept(Datum)函数的指针,客户自己添加进入通知列表,并且通过使用相同的指针调用取消订阅从列表中删除。当AbstractSubject决定通知它的客户时,notify()函数遍历客户列表,调用指向函数,传递相关数据。AbstractClient提供accept(Datum)函数接收和处理进入的数据。

《C嵌入式编程设计模式》---读书笔记(3)

3.5.4 协作模式

3.5.4.1 抽象客户接口

    AbstractClient与AbstractSubject有关联,以便它能调用后者的各种服务。它包含accept(Datum)函数,当AbstractClient订阅时或AbstractSubject认为是和发送数据时调用它。AbstractClient虽然指定函数但是不提供任何实现,它通过一组ConcreteClients实现提供对获取到的数据的操作。除了accept(Datum)函数外,AbstractClinet还与数据有关联,可以通过指针实现或通过栈、全局变量以及静态变量实现。

3.5.4.2 AbstractSubject接口

  在该模式中AbstractSubject是数据服务器,它提供3个服务:

  •     subscribe(acceptPtr)服务,添加指向接收函数通知列表的指针。如果成功返回零,失败为非零。
  •     unsubscribe(acceptPtr)服务,从通知列表中删除接收功能。如果成功返回零,失败为非零。
  •     notify()服务,遍历通知列表来通知订阅客户。通过调用每个通知句柄的指向函数实现。

    AbstractSubject也包括一个传递Datum的链接以及NotificationHandles列表。在这里,NotificationHandles列表使用指针数组实现。

3.5.4.3 ConcreteClient

    ConcreteClient是具体的AbstractClient接口的实现,提供acceptPtr(Datum)函数的实现以及其他与模式本身不相干功能。

3.5.4.4 ConcreteSubject

    ConcreteSubject是AbstractSUbject接口的具体实现。它不仅提供函数的实现,而且提供获取和管理发布数据的方法。ConcreteSubject不仅可以是AbstractSubject以外,通常也是HardwareProxy。

3.5.4.5 Datum

    该元素是客户或者对象感兴趣数据的替身。

3.5.4.6 NotificationHandle

    NotificationHandle是调用客户的accept(Datum)方法的代表,最常见的实现是函数指针。

3.5.5 效果

    观察者模式是一个给一组在设计时还不明确的客户分发数据的过程,同时还可以在运行时动态地管理感兴趣客户列表。该模式维护基本的客户机-服务器模型,通过它的订阅机制提供运行时的灵活性。为实现客户仅在适当的时候更新,最常见的策略是当数据改变时更新客户。

3.5.6 实现策略

    该模式唯一复杂的方面是通知句柄的实现,以及通知句柄列表的管理,通知句柄本身通常是一个回调函数。句柄因返回不同数据而不同,但是他依赖于软件"类"的实现。如果使用带有me指针的结构体的方式,me指针将会是接收函数的第一个参数。如果使用传统C编写,则ConcreteClients的实现会更加标准,而在接收函数列表中将不必包含me指针。

    通知列表可以采用定义数组的方式包含所有潜在客户,但在有多客户的高度动态系统中也可以使用链表构建系统。

3.5.7 相关模式

    在嵌入式系统中,将观察者功能添加到硬件代理或者硬件适配器模式中是非常普遍的。

3.5.8 实例

    如下图所示,在实例中GasSensor是模式的ConcreteClient,它提供订阅和取消订阅函数,并且管理GasNotificationHandles数组。除了subscribe()和unsubscribe()操作外,notidy()函数遍历已注册的订阅者列表,并使用简单的语句调用accept()操作。

me->itsGasHN[pos]->acceptorPtr(me->itsGasNH[pos]->instancePtr.me->itsGasData);

    在这种方式中,被指向的函数是通过函数指针访问的,其中第一个参数是客户的数据实例,第二个参数是指向新数据的指针。GasSensor类也包括newData()方法,它调用notify()方法和dumpList()方法,输出目前订阅的客户的列表。