Ada多态回调问题:Observer模式中访问子程序类型不匹配
Ada Observer模式中访问子程序类型不匹配问题
尝试使用OOP和动态调度实现Observer模式时,遇到无法创建访问子程序常量的问题:命名访问类型的参数与类型扩展的过程参数不匹配。以下是最小复现示例(省略订阅逻辑):
Alarms包定义
package Alarms is type time_t is mod 2**32; type AlarmObserver_t is interface; type Callback_t is access procedure (this : in out AlarmObserver_t); type AlarmPublisher_t (<>) is tagged limited private; function fConstructor (capacity : in Positive) return AlarmPublisher_t; private type AlarObserverAcc_t is access AlarmObserver_t'Class; type dummy_t is new AlarmObserver_t with null record; procedure pEventDummy (this : in out dummy_t) is Null; dummy : constant AlarObserverAcc_t := new dummy_t; dummyCallback : constant Callback_t := pEventDummy'Access; -- *此处编译失败* type Node_t is limited record Observer : AlarObserverAcc_t := dummy; Callback : Callback_t := dummyCallback; time : time_t := time_t'Last; end record; defaultNode : constant Node_t := Node_t' (Observer => dummy, Callback => dummyCallback, time => time_t'Last); type ObserverArray_t is array (Positive range <>) of Node_t; type AlarmPublisher_t (capacity : Positive) is tagged limited record -- 成员"observers"拥有默认初始化,因为Node_t已初始化 observers : ObserverArray_t (Positive'First .. capacity); end record; end Alarms;
Alarms包体实现
package body Alarms is function fConstructor (capacity : in Positive) return AlarmPublisher_t is begin return Obj : AlarmPublisher_t (capacity => capacity) do Null; end return; end fConstructor; end Alarms;
参考过Matthew Heaney的回调式Observer模式实现,他使用了类范围参数的访问子程序,但我希望采用OOP语法,让具体观察者将这些过程作为原语实现。
疑问
为什么dummy_t实现了AlarmObserver_t接口,但pEventDummy却无法与Callback_t兼容?能否实现我的预期需求?
预期需求
希望具体观察者能灵活订阅告警到期时想要接收通知的方法,无需预先将所有可能的方法定义为AlarmObserver_t接口的抽象原语,而是让具体观察者订阅对应的访问子程序,在不同时机接收通知。示例如下:
ConcreteObserver包示例
with Alarms; package ConcreteObserver is type ConcreteObserver_t is new Alarms.AlarmObserver_t with private; -- 告警到期时接收通知的evTimeout过程 -- 空实现用于编译 procedure evTimeout (this : in out ConcreteObserver_t) is null; -- 另一种告警到期时接收通知的evAnotherTimeout过程 -- 空实现用于编译 procedure evAnotherTimeout (this : in out ConcreteObserver_t) is null; private -- *此处编译失败,与Alarms包中的dummyCallback问题相同* evTimeoutCallback : constant Alarms.Callback_t := evTimeout'Access; -- *此处编译失败,与Alarms包中的dummyCallback问题相同* evAnotherTimeoutCallback : constant Alarms.Callback_t := evAnotherTimeout'Access; type ConcreteObserver_t is new Alarms.AlarmObserver_t with record -- 自定义属性 Null; end record; end ConcreteObserver;
内容的提问来源于stack exchange,提问作者Albatros23
相关产品推荐
相关产品推荐

