(上下文和问题,帖子底部的骨架代码)
我们正在创建和实现一个在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