我想实现一个不改变模型的模型类的观察者。因此,它应该能够使用常量引用来访问模型。但是观察员的注册禁止这样做。
下面是观察者模式在我的项目中是如何实现的:
//Attributes of type Observable are used by classes that want to notify others
//of state changes. Observing Objects register themselves with AddObserver.
//The Observable Object calls NotifyObservers when necessary.
class Notifier
{
public:
AddObserver(Observer*);
RemoveObserver(Observer*);
NotifyObservers();
};
class Model
{
public:
Notifier& GetNotifier() //Is non const because it needs to return a non-const
{ //reference to allow Observers to register themselves.
return m_Notifier;
}
int QueryState() const;
void ChangeModel(int newState)
{
m_Notifier.NotifyObservers();
}
private:
Notifier m_Notifier;
};
//This View does not Modify the Model.
class MyNonModifingView : public Observer
{
public:
SetModel(Model* aModel) //should be const Model* aModel...
{
m_Model = aModel;
m_Model->GetNotifier().AddObserver(this); //...but can't because
//SetModel needs to call GetNotifier and add itself, which requires
//non-const AddObserver and GetNotifier methods.
}
void Update() //Part of Observer-Interface, called by Notifiers
{
m_Model->QueryState();
}
};
非修改观察者唯一需要“改变”模型的地方是它想要注册的时候。我觉得我无法避免这里的const_cast,但我想知道是否有更好的解决方案。
旁注: 换句话说,我不认为模型对象管理的“观察者列表”是模型状态的一部分。 C++ 无法区分并将状态和观察者混为一谈,强制两者为常量或非常量。
干杯,菲利克斯
最佳答案
如果您认为通知程序对象不是拥有它的模型对象的一部分,因此修改通知程序不会“算作”修改模型,那么让 getNotifier 成为返回非常量引用的常量方法:
Notifier& GetNotifier() const //Is const but returns a non-const
{ //reference to allow Observers to
//register themselves.
return m_Notifier;
}
然后您必须将 m_Notifier 标记为可变的,或者通过指针(或智能指针)或引用而不是包含来拥有它。无论哪种方式,您都可以避免使用 const_cast。通常最好嵌入对象而不是指向/引用它们,但如果在这种情况下通知程序不被视为使用它的模型的一部分,则嵌入不是必需的。通过引用拥有它会强制您在构造模型时初始化引用,这会导致依赖注入(inject),这不是坏事。通过智能指针拥有意味着,与嵌入一样,您不必做任何清理工作。
可能还有其他设计方法(例如 Vinay 添加了另一个类),但您的评论“是非常量,因为它需要返回非常量引用”向我表明您可以完全按照自己的意愿行事最初想要,只是你没有意识到你可以。
关于c++ - 观察者模式中的 Const-correct 通知程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/725375/