2

Model を変更しない Model クラスの Observer を実装したいと考えています。したがって、const-Reference を使用してモデルにアクセスできる必要があります。しかし、オブザーバーの登録はこれを禁止しています。

私のプロジェクトでオブザーバーパターンを実装する方法は次のとおりです。



//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 または非 const に強制します。

乾杯、フェリックス

4

6 に答える 6

5

Notifier オブジェクトがそれを所有する Model オブジェクトの一部ではないと考える場合は、Notifier の変更が Model の変更として「カウント」されないようにするには、getNotifier を非 const 参照を返す const メソッドにします。

Notifier& GetNotifier() const //Is const but returns a non-const 
{                             //reference to allow Observers to 
                              //register themselves.

     return m_Notifier; 
}

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

物事を設計する他の方法があるかもしれません (Vinay の別のクラスの追加など) が、「非 const 参照を返す必要があるため、非 const です」というコメントは、最初に望んでいたことを正確に行うことができることを示唆しています。できることに気づいていないだけです。

于 2009-04-07T12:48:15.470 に答える
1

私の他の答えへの代替アプローチ。

オブザーバーにモデルへのポインターを持たせないでください。const *Model通知機能によって呼び出されるupdateメソッドにaを渡します。これは、通知するモデルを知る必要がありますが、モデルに埋め込まれていることを考えると、おそらく難しいことではないので、おそらく常にそのモデルです...

オブザーバーがSetModelで非constモデルを必要とする場合でも、それを与えることができますが、SetModelを完全に削除し、のsome_model.AddObserver(some_observer)代わりに呼び出す可能性が高くなりますsome_observer.SetModel(some_model)

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

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

于 2009-04-07T13:00:49.993 に答える
1

代わりは

view->SetModel( model ); 

あなたは電話することができます

model->getNotifier()->addObserver( view );
view->setModel( model ); // this function will accept const Model*
于 2009-04-07T12:42:34.530 に答える
0

コントローラーがこれを解決することを期待しています:

1.Controller は Model を認識し、View を Model に登録できるようにします。

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. MyNonModifingView を const Model* aModel を受け入れるように変更します

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();
    }

};
于 2009-04-07T13:18:13.197 に答える