私の2セント...
クラシック(四人組)の実装は、対象のいかなる性質の変化にオブザーバを通知します。あなたの質問では、の特定のプロパティにオブザーバーを登録したいと思っています。 Observerパターンを1レベル下に移動して、プロパティを具体的なテーマとして取り込み、オブザーバーを(プロパティごとに)定義することができますが、この問題を解決する方法が1つあります。
In C#Observerパターンは、イベントとの代理人によって実装されています。デリゲートは、イベントハンドラを表します。イベントハンドラは、イベントが発生したときに実行する必要がある機能です。代理人は、イベントから追加(登録)または削除(登録解除)することができます。
C++では、ファンクタがデリゲートとして機能します。グローバル関数またはクラスメソッドを別のコンテキストで呼び出すために必要な情報をすべて格納できます。イベントは(登録された)ファンクタの集合であり、イベントが発生したとき(呼び出されるとき)は基本的にそのリストを通り、すべてのファンクタを呼び出します(juanchopanzaの解でPublisher::publish
メソッドを参照)。
イベントと代理人のC++バージョンを実装しようとしましたが、あなたのケースで適用できる修正されたオブザーバーパターンで使用しました。これは私が思い付いたものです:
#include <list>
#include <iostream>
#include <algorithm>
// use base class to resolve the problem of how to put into collection objects of different types
template <typename TPropertyType>
struct PropertyChangedDelegateBase
{
virtual ~PropertyChangedDelegateBase(){};
virtual void operator()(const TPropertyType& t) = 0;
};
template <typename THandlerOwner, typename TPropertyType>
struct PropertyChangedDelegate : public PropertyChangedDelegateBase<TPropertyType>
{
THandlerOwner* pHandlerOwner_;
typedef void (THandlerOwner::*TPropertyChangeHandler)(const TPropertyType&);
TPropertyChangeHandler handler_;
public:
PropertyChangedDelegate(THandlerOwner* pHandlerOwner, TPropertyChangeHandler handler) :
pHandlerOwner_(pHandlerOwner), handler_(handler){}
void operator()(const TPropertyType& t)
{
(pHandlerOwner_->*handler_)(t);
}
};
template<typename TPropertyType>
class PropertyChangedEvent
{
public:
virtual ~PropertyChangedEvent(){};
void add(PropertyChangedDelegateBase<TPropertyType>* const d)
{
std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
if(it != observers_.end())
throw std::runtime_error("Observer already registered");
observers_.push_back(d);
}
void remove(PropertyChangedDelegateBase<TPropertyType>* const d)
{
std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
if(it != observers_.end())
observers_.remove(d);
}
// notify
void operator()(const TPropertyType& newValue)
{
std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = observers_.begin();
for(; it != observers_.end(); ++it)
{
(*it)->operator()(newValue);
}
}
protected:
std::list<PropertyChangedDelegateBase<TPropertyType>* const> observers_;
};
// class that owns concrete subjects
class PropertyOwner1
{
int property1_;
float property2_;
public:
PropertyChangedEvent<int> property1ChangedEvent;
PropertyChangedEvent<float> property2ChangedEvent;
PropertyOwner1() :
property1_(0),
property2_(0.0f)
{}
int property1() const {return property1_;}
void property1(int n)
{
if(property1_ != n)
{
property1_ = n;
std::cout << "PropertyOwner1::property1(): property1_ set to " << property1_ << std::endl;
property1ChangedEvent(property1_);
}
}
float property2() const {return property2_;}
void property2(float n)
{
if(property2_ != n)
{
property2_ = n;
std::cout << "PropertyOwner1::property2(): property2_ set to " << property2_ << std::endl;
property2ChangedEvent(property2_);
}
}
};
// class that owns concrete subjects
class PropertyOwner2
{
bool property1_;
double property2_;
public:
PropertyChangedEvent<bool> property1ChangedEvent;
PropertyChangedEvent<double> property2ChangedEvent;
PropertyOwner2() :
property1_(false),
property2_(0.0)
{}
bool property1() const {return property1_;}
void property1(bool n)
{
if(property1_ != n)
{
property1_ = n;
std::cout << "PropertyOwner2::property1(): property1_ set to " << property1_ << std::endl;
property1ChangedEvent(property1_);
}
}
double property2() const {return property2_;}
void property2(double n)
{
if(property2_ != n)
{
property2_ = n;
std::cout << "PropertyOwner2::property2(): property2_ set to " << property2_ << std::endl;
property2ChangedEvent(property2_);
}
}
};
// class that observes changes in property1 of PropertyOwner1 and property1 of PropertyOwner2
struct PropertyObserver1
{
void OnPropertyOwner1Property1Changed(const int& newValue)
{
std::cout << "\tPropertyObserver1::OnPropertyOwner1Property1Changed(): \n\tnew value is: " << newValue << std::endl;
}
void OnPropertyOwner2Property1Changed(const bool& newValue)
{
std::cout << "\tPropertyObserver1::OnPropertyOwner2Property1Changed(): \n\tnew value is: " << newValue << std::endl;
}
};
// class that observes changes in property2 of PropertyOwner1 and property2 of PropertyOwner2
struct PropertyObserver2
{
void OnPropertyOwner1Property2Changed(const float& newValue)
{
std::cout << "\tPropertyObserver2::OnPropertyOwner1Property2Changed(): \n\tnew value is: " << newValue << std::endl;
}
void OnPropertyOwner2Property2Changed(const double& newValue)
{
std::cout << "\tPropertyObserver2::OnPropertyOwner2Property2Changed(): \n\tnew value is: " << newValue << std::endl;
}
};
int main(int argc, char** argv)
{
PropertyOwner1 propertyOwner1;
PropertyOwner2 propertyOwner2;
PropertyObserver1 propertyObserver1;
PropertyObserver2 propertyObserver2;
// register observers
PropertyChangedDelegate<PropertyObserver1, int> delegate1(&propertyObserver1, &PropertyObserver1::OnPropertyOwner1Property1Changed);
propertyOwner1.property1ChangedEvent.add(&delegate1);
PropertyChangedDelegate<PropertyObserver2, float> delegate2(&propertyObserver2, &PropertyObserver2::OnPropertyOwner1Property2Changed);
propertyOwner1.property2ChangedEvent.add(&delegate2);
PropertyChangedDelegate<PropertyObserver1, bool> delegate3(&propertyObserver1, &PropertyObserver1::OnPropertyOwner2Property1Changed);
propertyOwner2.property1ChangedEvent.add(&delegate3);
PropertyChangedDelegate<PropertyObserver2, double> delegate4(&propertyObserver2, &PropertyObserver2::OnPropertyOwner2Property2Changed);
propertyOwner2.property2ChangedEvent.add(&delegate4);
propertyOwner1.property1(1);
propertyOwner1.property2(1.2f);
propertyOwner2.property1(true);
propertyOwner2.property2(3.4);
// unregister PropertyObserver1
propertyOwner1.property1ChangedEvent.remove(&delegate1);
propertyOwner2.property1ChangedEvent.remove(&delegate3);
propertyOwner1.property1(2);
propertyOwner1.property2(4.5f);
}
出力:
が各観測者が特定のプロパティに登録され、通知された場合、各観察者が知っている
PropertyOwner1::property1(): property1_ set to 1
PropertyObserver1::OnPropertyOwner1Property1Changed():
new value is: 1
PropertyOwner1::property2(): property2_ set to 1.2
PropertyObserver2::OnPropertyOwner1Property2Changed():
new value is: 1.2
PropertyOwner2::property1(): property1_ set to 1
PropertyObserver1::OnPropertyOwner2Property1Changed():
new value is: 1
PropertyOwner2::property2(): property2_ set to 3.4
PropertyObserver2::OnPropertyOwner2Property2Changed():
new value is: 3.4
PropertyOwner1::property1(): property1_ set to 2
PropertyOwner1::property2(): property2_ set to 4.5
PropertyObserver2::OnPropertyOwner1Property2Changed():
new value is: 4.5
の所有者である正確にプロパティとプロパティの新しい値です。
'Subject 'は、' Subject'のプロパティにどのオブザーバが関心があるのかを知るべきではありません。 'ConcreteObserver'はそれらが興味を持っているものを知っています。' ConcreteSubject'はpublic getterを持っていなければなりません。 'ConcreteObserver'はそれらのプロパティの最新値を取得できます(' ConcreteSubject'がイベントをトリガーするとき、 ()メソッド - Gang Of Four Observer実装用のGoogle)。 'registerObservers'はオブザーバのリストに新しい' ConcreteObserver'を追加するだけです。それぞれの 'ConcreteObserver'を複数の' ConcreteSubject'で登録することができます。 –
@BojanKomazec「公共ゲッター」とはどういう意味ですか?説明してください。サブジェクトが「通知」機能を呼び出すと、何が起こるはずですか? –
私はパブリックアクセサメソッドを意味します。下記のAquilaRapaxの答えを見て、 'WheatherData :: getTemperature()'、 'WheatherData :: getHumidity()'などを探してください。 'Notify()'は登録されているすべてのオブザーバのリストを調べ、その上で 'Update()'を呼び出します。それぞれの 'ConcreteObserver'は' Update() 'を実装し、このメソッドの中でそれらのゲッターを通して' ConcreteSubject'のプロパティの最新の値を取得します。 –