誰かが使ったらアリスに知らせろ

怒涛のアリプラシリーズをもうひとつ。

鞄に対してマーキングをするのは消極的な手段でして、マーキングを上書きされてしまったり、マーキング自体を無視して 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 のようにポインタのコレクションの場合は、所有自体を制限させるのはできないのかなと。写真みたいなものですから。肖像権を主張できても、対象そのものを写真で写すこを制限するのは難しい、っていう意味ですね。

カテゴリー: C++ パーマリンク