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