(上下文和问题,帖子底部的骨架代码)
我们正在创建和实现一个在Arduino等环境中使用的C框架.
为此,我想使用Observer模式,其中任何对传感器状态变化感兴趣的组件(Observables)都可以注册自己,Observable会通过调用Observer的notification()方法将其自身作为一个变更通知.参数.
一个观察者可以观察到多个Observable,反之亦然.
问题在于Observer需要提取Observable的当前状态并对其执行某些操作,并且此当前状态可以采用所有形式和大小,具体取决于Observable的特定传感器.
它当然可以是序数值,它们是有限的并且可以编码出来,就像我在下面的代码中用方法getValueasInt()所做的那样,但它也可以是传感器特定的结构,即对于RealTimeClock,它提供了一个结构日期和时间值.结构当然在编译时定义,并针对特定传感器进行修复.
编辑:请注意,dynamic_cast<>由于Arduino的限制,结构是不可能的
我创建了以下类层次结构(框架代码):
class SenseNode { public: SenseNode() {}; SenseNode(uint8_t aNodeId): id(aNodeId) {} virtual ~SenseNode() {} uint8_t getId() { return id; }; private: uint8_t id = 0; }; class SenseStateNode : virtual public SenseNode { public: SenseStateNode(uint8_t aNodeId) : SenseNode(aNodeId) {} virtual ~SenseStateNode() {} /** Return current node state interpreted as an integer. */ virtual int getValueAsInt(); }; class SenSEObservable: public SenseStateNode { public: SenSEObservable(uint8_t aNodeId); virtual ~SenSEObservable(); /** Notify all interested observers of the change in state by calling Observer.notification(this) */ virtual void notifyObservers(); protected: virtual void registerObserver(SenSEObserver *); virtual void unregisterObserver(SenSEObserver *); }; class SenSEObserver: virtual public SenseNode { public: SenSEObserver() {}; virtual ~SenSEObserver(); /** Called by an Observable that we are observing to inform us of a change in state */ virtual void notification(SenSEObservable *observable) { int v = observable->getValueAsInt(); // works like a charm DateTime d = observable-> ???? // How should i solve this elegantly? }; };
解决方法
如果传感器类型的数量或多或少稳定(并且它是 – 在大多数情况下变化非常罕见) – 那么只需在Observer端准备以获得几种通知:
class Observer { public: virtual void notify(SenseNode& node) { // implement here general actions - like printing: not interested in this } virtual void notify(RealTimeClock& node) { notify(static_cast<SenseNode&>(node)); // by default go to more general function } // and follow this pattern - for all nodes you want to handle // add corresponding notify(T&) function };
当它发生时你必须添加新的节点类型 – 然后只需将新的虚函数添加到你的基础Observer类.
要在Observable端实现此机制 – 使用double dispatch pattern:
class SenseNode { public: virtual void notifyObserver(Observer& observer) { observer.notify(*this); } }; class RealTimeClock : public virtual SenseNode { public: virtual void notifyObserver(Observer& observer) { observer.notify(*this); // this will select proper Observer::notify(RealTimeClock&) // because *this is RealTimeCLock } }; class SenSEObservable: public SenseStateNode { public: virtual void notifyObservers() { for (auto& observer : observers) notifyObserver(observer); } };
它在实践中如何运作,见live demo