怒涛のアリプラシリーズをもうひとつ。
鞄に対してマーキングをするのは消極的な手段でして、マーキングを上書きされてしまったり、マーキング自体を無視して Use メソッドを呼び出したりするとアリスはお手上げです。なので、もっと積極的に違法な Use メソッドが呼び出されたら、アラートメッセージがアリスに届くようにします。
そう、mvvm パターンの INotifyPropertyChanged と同じです。
// for 誰かが使ったらアリスに知らせろ #include <iostream> #include <list> using namespace std; class ICatch { public: virtual void OnTatch( void *bag ) = 0; }; class INotify { protected: ICatch *catcher; public: void setCatcher( ICatch *user ) { catcher = user; } virtual void OnTatch( void *bag ) { if ( catcher != NULL ) { catcher->OnTatch( bag ); } } }; class Bag : public INotify { protected: void *_mark; public: Bag() : _mark(NULL) {} virtual void setMark( void *mark ) { // 1回だけマークできる if ( _mark == NULL ) { _mark = mark; } } virtual void *getMark() { return _mark; } virtual void Used( void *user ) { if ( _mark != NULL && _mark != user ) { OnTatch( this ); } } }; class Prada : public Bag {}; class Tiffany : public Bag {}; class Alice : public ICatch { private: list<Bag*> bags; public: Alice() { } void Present( Bag *bag ) { if ( dynamic_cast<Prada*>(bag) != NULL && bag->getMark() == NULL ) { bag->setMark( this ); bag->setCatcher( this ); bags.push_back( bag ); } } int CountBags() { return bags.size(); } void Use( Bag *bag ) { bag->Used( this ); } virtual void OnTatch( void *bag ) { cout << "who use my Prada bag!!!" << endl; } }; class Lolita { private: list<Bag*> bags; public: void Present( Bag *bag ) { bag->setMark( this ); bags.push_back( bag ); } void Use( Bag *bag ) { bag->Used( this ); } }; int main(void) { Alice alice; Lolita lolita; Prada *bag = new Prada(); // アリスにプレゼント alice.Present( bag ); // アリスが使う分には問題なし alice.Use( bag ); // 同じ鞄をロリータにプレゼント lolita.Present( bag ); // ロリータが鞄を使うと... lolita.Use( bag ); return 0; }
鞄(Bag)のほうには、INotiry インターフェースを仕込んでおきます。アラートメッセージをを受け取る側(Alice)のほうは、ICatch インターフェースで受け取りの関数を用意しておきます。C++ で2つのインターフェースを使っているのは C# のデリゲートの機能がないので、こうなっています。static な関数ポインタを用意してもいいのですが、どうせならば、Alice のメソッドとして用意したいところですよね。
実は、モノである鞄(Bag)に機能を仕掛けておいて、人であるアリスに通知する、ってのがいい感じかなと。
これを実行すると、
D:\work\blog\src\alice>a who use my Prada bag!!!
誰か私のバッグを使ったッ!!!って怒ります。ロリータからは Use メソッドの中身は見れないし、そもそも Lolita は ICatch を継承してないのでアラートメッセージを受け取りません。
似たようなパターンとしては、
- Bag クラスのデストラクタに仕込んで、なんで、私の鞄を捨てるのよッ!!!とか。
- List
を改造して、なんで、私の鞄を持っているのよッ!!!とか
ができます。鞄というオブジェクトはひとつなので、Alice::bags と Lolita::bags の両方にあるってのは妙な感じですよね。実際は、ポインタが使われているので、鞄そのものが置いてあるというよりも、鞄を示すタグ(所有権)を撮り廻しているっていう意味になりますが。鞄そのものは実体なのでひとつしかないけど、ポインタ(指し示すもの)は、いくらでもできるから list