I want to implement an Observer of a Model class which does not change the Model. Thus, it should be able to use a const-Reference to access the Model. But the Registering of the Observer prohibits this.
Here is how the observer pattern is implemented in my Project:
//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();
}
};
The only place where a non-modifying observer needs to "change" the Model is when it wants to register with it. I feel that I can not avoid a const_cast here, but I wanted to know if there are better solutions.
Sidenote: Put another way, I don't consider the "List of Observers" which a model object manages to be part of the state of the Model. C++ can not tell the difference and lumps state and observers together, forcing both to be const or non-const.
Cheers, Felix
If you consider the Notifier object not to be part of the Model object which owns it, so that modifying the Notifier doesn't "count" as modifying the Model, then make getNotifier a const method returning a non-const reference:
Notifier& GetNotifier() const //Is const but returns a non-const
{ //reference to allow Observers to
//register themselves.
return m_Notifier;
}
You will then have to either mark m_Notifier as mutable, or else own it by pointer (or smart pointer) or reference rather than by inclusion. Either way, you avoid a const_cast. It is usually preferable to embed objects rather than point/refer to them, but if this is a case where a Notifier isn't considered part of the Model which uses it, then embedding is not essential. Owning it by reference forces you to initialize the reference when Model is constructed, which leads to dependency injection, which is no bad thing. Owning by smart pointer means that, as with embedding, you don't have to do anything about cleanup.
There may be other ways to design things (such as Vinay's addition of another class), but your comment "Is non-const because it needs to return a non-const reference" suggests to me that you can do exactly what you originally wanted, you just don't realise you can.
I'm not clear from your code, but if you have a member that is logically const, but physically non-const, the usual solution is to make it mutable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With