web-dev-qa-db-ja.com

オブザーバーパターン。 *何が*変更されたか知っていますか?

古典的なObserverパターンインターフェイスを定義する2つの抽象クラスSubjectとObserverを作成しました。私はそれらから派生してObserverパターンを実装します。オブザーバーは次のようになります。

void MyClass::Update(Subject *subject)
{
    if(subject == myService_)
    {
        DoSomething();
    }
    else if(subject == myOtherService_)
    {
        DoSomethingElse();
    }
}

これは問題なく、 who が何かを変更したことがわかります。ただし、 what が変更されたことがわかりません。サブジェクトに最新のデータを照会するだけでよい場合もありますが、サブジェクトで正確に何が変更されたかを知る必要がある場合もあります。 Javaには、notifyObservers()メソッドと notifyObservers(Object arg) メソッドの両方があり、変更内容の詳細をおそらく指定していることに気づきました。

私の場合、サブジェクトで2つの異なるアクションの1つが発生したかどうかを知り、それが特定のアクションの場合は、そのアクションに関連する整数を知る必要があります。

だから私の質問は:

  1. (Javaがするように)一般的な引数を渡すC++の方法は何ですか?
  2. オブザーバーは最高のパターンですか?たぶん、ある種のイベントシステム?

[〜#〜]更新[〜#〜]

Observerパターンのテンプレート化について説明しているこの記事を見つけました: テンプレートを使用したSubject/Observerパターンの実装 。これは私があなたが議論をテンプレート化できるかどうか疑問に思いました。

引数のテンプレート化について説明するこのスタックオーバーフローの質問が見つかりました: テンプレートベースのサブジェクトオブザーバーパターン-static_castまたはdynamic_castを使用する必要があります 。しかし、OPには誰も答えていない問題があるようです。

もう1つの方法は、Updateメソッドを変更して、次のようにEventArgオブジェクトを取得することです。

void MyClass::Update(Subject *subject, EventArg arg)
{
  ...

次に、特定の引数データ用にEventArgのサブクラスを作成し、それをupdateメソッド内の特定のサブクラスにキャストバックします。

更新2

また、 what の変更について件名に詳細を伝えることについて説明している記事 非同期メッセージベースのc ++フレームワークの作成について、パート2 も見つけました。

Boost.Signals の使用を真剣に検討しています。単純なときに自分のオブザーバーパターンを使用することは理にかなっていますが、型と引数のテンプレート化は複雑になり始めています。そして、Boost.Signals2のスレッドセーフが必要になる場合があります。

更新3

オブザーバーパターンに関する興味深い記事もいくつか見つけました。

ハーブサッターによるオブザーバーの一般化

C++でのオブザーバーパターンの実装-パート1

オブザーバーデザインパターンの実装の経験(パート2)

オブザーバーデザインパターンの実装の経験(パート3)

ただし、私は実装をBoost.Signalsを使用するように切り替えましたが、目的のために少し肥大化している可能性がありますが、正常に機能しています。そして、おそらく膨らみや速度の懸念は無関係です。

10
User

C++でもJavaでも、オブザーバーへの通知canwhatの情報とともに変更されます。同じメソッドnotifyObservers(Object arg)もC++で使用できます。

一般に、問題は残ります。1人または複数のオブザーバーに複数のサブジェクトがディスパッチする可能性があるため、class argはハードコードできません。

通常、最善の方法は、さまざまなクラスに対して同じデータ型を形成する一般的なメッセージ/トークンの形式でargを作成することですが、観測されるクラスによって値が異なります。あるいは、すべてのそのような通知値が、すべてに共通のいくつかのベースクラスのクラスから導出される場合。

オブザーバーパターンの場合、Argデータタイプがオブザーバーとオブザーバー間でハードコーディングされていないことが重要です。

[〜#〜]編集[〜#〜]
オブザーバーが観察するだけでなく、何が変更されたかに基づいて他の多くのタスクを実行する必要がある場合は、ビジターパターン。ビジターパターンでは、オブザーバー/ビジターが変更されたオブジェクトを呼び出すため、変更内容を知るだけでなくだけでなく実際にそれに取り組む

4
Dipan Mehta

C++で「Java Like」汎用イベント引数を送信する方法はいくつかあります。

1)イベント引数をvoid *として宣言し、イベントハンドラーの適切なクラスにキャストします。

2)イベント引数を(例に応じて)などの新しいクラス/インターフェースへのポインタ/参照として宣言します。

class GenericEventArgument
{
  virtual bool didAction1Happen() = 0;
  virtual int getActionInteger() = 0;
};

そして、実際のイベント引数クラスがこのクラスから派生するようにします。

テンプレートベースのオブザーバーに関する質問はチェックアウトしてください

http://www.codeproject.com/Articles/3267/Implementing-a-Subject-Observer-pattern-with-templ

0
Gonen I