Observer
で,何とか実装してみました.
#include <list> #include <algorithm> #include <assert.h> #include <iostream> class subject; // // Observerクラス // class observer { protected: observer(){ } public: virtual ~observer(){} // 変更があった時(notify)subjectから呼ばれる virtual void subject_update(subject* sub) = 0; // observerが登録された時,登録したsubjectから呼ばれる virtual void subject_set(subject* sub) = 0; // observerが解除された時,解除したsubjectから呼ばれる virtual void subject_unset(subject* sub) = 0; }; // // Subjectクラス // class subject { protected: std::list<observer*> observers_; subject(){} public: virtual ~subject(){} virtual void attach(observer* obs){ // 登録した自分をobserverに教え,observerを登録 obs->subject_set(this); observers_.push_back(obs); } virtual void detach(observer* obs){ // 解除した自分をobserverに教え,observerを解除 obs->subject_unset(this); observers_.remove(obs); } virtual void notify(){ // Notify! std::list<observer*>::iterator it = observers_.begin(); for(; it != observers_.end(); ++it) (*it)->subject_update(this); } }; // // ConcreteSubjectクラス // class data : public subject { int n; public: ~data(){ // 登録しているobserversに自分が消えることを教える(解除) std::list<observer*>::iterator it = observers_.begin(); for(; it != observers_.end(); ++it) (*it)->subject_unset(this); } void set(int x){ n = x; notify(); } int get(){ return n; } }; // // ConcreteObserverクラス // class viewer : public observer { std::list<data*> data_; public: viewer(){} ~viewer(){ // 自分を登録しているsubjectに対し,自分をdetachする std::list<data*>::iterator it = data_.begin(); while(it != data_.end()) (*it++)->detach(this); } void subject_update(subject* sub){ std::list<data*>::iterator it = std::find(data_.begin(), data_.end(), sub); assert(it != data_.end()); // dynamic_cast failed! std::cout << "data is " << (*it)->get() << std::endl; } void subject_set(subject* sub){ assert(std::find(data_.begin(), data_.end(), sub) == data_.end()); // まだ登録されてないはず data* new_data = dynamic_cast<data*>(sub); assert(new_data != NULL); // dynamic_cast failed! data_.push_back(new_data); } void subject_unset(subject* sub){ assert(std::find(data_.begin(), data_.end(), sub) != data_.end()); // 登録されているはず data_.remove(sub); } };
コメントが無い….
微妙なコメントをちょっとつけた.
これでダングリングにも対応できるかな?
うーん,使用用途にもよるだろうけど,std::vectorの方がいい気がする.
viewer::~viewer()内で無効なイテレータを操作していた.
気付かないうちになっちゃうもんだね(detach内で普通にeraseしてるが).