怒涛のアリプラシリーズをもうひとつ。
鞄に対してマーキングをするのは消極的な手段でして、マーキングを上書きされてしまったり、マーキング自体を無視して 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
