2009-04-07 14 views
2

モデルを変更しないModelクラスのObserverを実装したいと思います。したがって、モデルにアクセスするためにconst-Referenceを使用できるはずです。しかし、オブザーバーの登録はこれを禁止します。ここでObserverパターンのConst-Not Notifier

はオブザーバーパターンは私のプロジェクトで実装されている方法です。

 


//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++は、違いを知ることができず、状態とオブザーバを一緒にして、constとnon-constの両方を強制します。

は乾杯、フェリックス

答えて

5

を呼び出すことができますモデルを変更する場合は、getNotifierをconst以外の参照を返すconstメソッドにします。

次に、m_Notifierをmutableとマークするか、またはそれをインクルードではなくポインタ(またはスマートポインタ)または参照で所有する必要があります。いずれにしても、const_castは避けてください。通常、オブジェクトをポイント/参照するのではなく、オブジェクトを埋め込むことが望ましいですが、Notifierがそれを使用するモデルの一部とみなされない場合は、埋め込みは必須ではありません。参照によってそれを所有することは、モデルが構築されたときに参照を初期化するように強制します。これは依存性注入につながりますが、これは悪いことではありません。スマートポインタを持つことは、埋め込みの場合と同様に、クリーンアップについて何もする必要がないことを意味します。

(Vinayの別のクラスの追加など)他の方法があるかもしれませんが、あなたのコメント「非const参照を返す必要があるため非constです」は、あなたが元々望んでいた、あなたはあなたができることを理解していない。

+0

私は変更可能で行った。私は以前はさまざまな理由でNotificationMediatorを注入することを検討していましたが、これは今のところ大きな混​​乱の原因となります。 – TheFogger

3

私はあなたのコードから明らかでないんだけど、あなたは論理的にconstのあるメンバーが、物理的に非constを持っている場合、通常の解決策は、それ可変ようにすることです。

0

constモデルを返す代わりに、NotifierオブジェクトをラップしてNotifierを実装するもう1つのクラスを作成できます。 (アダプタパターン)。オブザーバーは、新しく作成したクラスを登録/登録解除に使用できます。通知を変更すると、「カウントをしないようにあなたは、通知オブジェクトは、それを所有しているモデルオブジェクトの一部ではないと考える場合

+0

私はこれがどのように動作するかを得ることはありません。確かに、アダプターは、非constにする必要のあるアダプターへの参照を保持するでしょう。もし私がこのような参照を持っていれば、私はそれを直接使うことができます。 – TheFogger

1

代わり

view->SetModel(model); 

あなたは

model->getNotifier()->addObserver(view); 
view->setModel(model); // this function will accept const Model* 
+0

私はこれが本当に好きですが、このプロジェクトではコントローラはビ​​ューに統合されていますが、通常は別々のクラスにはありません。 – TheFogger

1

私の他の答えに対する別のアプローチです。

オブザーバにモデルへのポインタを保持させないでください。 const *Modelを、通知メソッドによって呼び出される更新メソッドに渡します。これは、どのモデルが通知されているかを知る必要がありますが、モデルに埋め込まれているとすればおそらくそれほど難しくありません。

ObserverがSetModelで非constモデルを必要とする場合でも、それを1つでも与えることができますが、SetModelを完全になくし、some_observer.SetModel(some_model)の代わりにsome_model.AddObserver(some_observer)を呼び出します。

同様に、それほど徹底的には、物事をそのまま残すことができますが、const *Model m_Modelと宣言してください。次に、aModelをSetModelの非constモデルとして使用できますが、オブザーバの他のメソッドでモデルを変更することはできません。

Observerが使用するパラメータなしで自身を登録解除できると予想される場合、これらの変更はどちらも機能しません。

0

私はコントローラがこの問題を解決することを期待:

1.Controllerはモデルを知っていて、ビュー登録はモデル化することができます。

class MyController 
{ 
public: 

    //Controller associated with the Model 
    MyController(Model* pModel):m_pModel(pModel) 
    { 
    } 

    //Provide the facility to register the view. 
    //Alternatively, if there is 1:1 relation between controller and View then View poniter can be stored locally inside Controller 
    void registerObserver(Observer* pObserver) 
    { 
       //Register observer 
     m_pModel->GetNotifier().AddObserver(pObserver); 
       //set the model in view 
     pObserver->SetModel(m_pModel); 

    } 
}; 

2.Change constのモデルを受け入れるMyNonModifingView *アモデル

class MyNonModifingView : public Observer 
{ 
public: 
    SetModel(const Model* aModel) 
    { 
     m_Model = aModel; 
    //NO need to register here, My controller does it for me. 
     // m_Model->GetNotifier().AddObserver(this); 
    } 

    void Update() //Part of Observer-Interface, called by Notifiers 
    { 
     m_Model->QueryState(); 
    } 

}; 
+0

私はこれが好きですが、私たちのコントローラは通常ビューに統合されています。 – TheFogger

関連する問題