アリスはプラダの中古がお嫌い | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/1442
前回、こんなところで中古のプラダを渡すと激怒して例外を発生させましたが、今回は大人しく false を返すことにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #include <iostream> class Bag { protected : bool used; public : Bag() : used( false ) {} virtual bool getUsed() { return used; } void Used() { Bag::used = true ; } }; class Prada : public Bag {}; class Tiffany : public Bag {}; // 中古が嫌いなアリス class Alice { public : bool DoYouLike( Bag *bag ) { if ( bag->getUsed() == true ) { return false ; } else { return true ; } } void Use( Bag *bag ) { bag->Used(); } }; // 悪友ロリータ class Lolita { public : bool DoYouLike( Bag *bag ) { return true ; } void Use( Bag *bag ) { bag->Used(); } }; using namespace std; int main( void ) { Alice alice; Lolita lolita; { Prada bag; if ( alice.DoYouLike( &bag ) ) { cout << "alice like New Prada." << endl; } else { cout << "alice don't like Used Prada." << endl; } } { Prada bag; lolita.Use( &bag ); // アリスは他人が使ったものが嫌い if ( alice.DoYouLike( &bag ) ) { cout << "alice like New Prada." << endl; } else { cout << "alice don't like Used Prada." << endl; } } { Prada bag; alice.Use( &bag ); // 自分が使っても嫌い??? if ( alice.DoYouLike( &bag ) ) { cout << "alice like New Prada." << endl; } else { cout << "alice don't like Used Prada." << endl; } } return 0; } |
ただし、これを実行するとですとね、
1 2 3 4 | D:\work\blog\src\alice>a alice like New Prada. alice don't like Used Prada. alice don't like Used Prada. |
な風に自分が使ったプラダの鞄も嫌いになってしまうのです。なので、
- 自分が使った鞄は中古でも OK(中古というよりも自分のものだし)
- 他人が使った鞄は嫌い
という判別を付けたいとすると。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Alice { public : Alice() {} bool DoYouLike( Bag *bag ) { if ( bag->getMark() == this || bag->getUsed() == false ) { return true ; } else { return false ; } } void Use( Bag *bag ) { bag->setMark( this ); bag->Used(); } }; |
のように、Use メソッド中であらかじめ自分の使っていた鞄のポインタを保存しておいて、DoYouLike メソッドではそれと比較します。自分のだったら OK って具合ですね。
このあたりのパターンは、自 Factory クラスで作ったオブジェクトは利用できるけど、他 Factiory クラスで作ったオブジェクトは弾くってな感じで使えます。独自 malloc なんかを作るとき、単純に free したりするとアウトになってしまうので、自分のかどうかを判別するわけです。このフラグは、オブジェクト自身に置いてもよいし、Factory クラス自身に置いても OK。どちらも、ポインタ分だけを消費しますが、作成されたオブジェクトのほうに置くほうが、自他の判別は早くなるのかなぁと。
マーキングを利用したパターンが以下です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class Bag { protected : bool used; void *_mark; public : Bag() : used( false ), _mark(NULL) {} virtual bool getUsed() { return used; } void Used() { Bag::used = true ; } // マーキング void setMark( void *mark ) { this ->_mark = mark; } void *getMark() { return _mark; } }; class Prada : public Bag {}; class Tiffany : public Bag {}; // 中古が嫌いなアリス class Alice { public : Alice() {} bool DoYouLike( Bag *bag ) { if ( bag->getMark() != this && bag->getUsed() == true ) { return false ; } else { return true ; } } void Use( Bag *bag ) { bag->setMark( this ); bag->Used(); } }; |
この場合は、Bag クラスを修正しないといけないので、ちょっと変な気もしますが、鞄に名前を付けておくとか、自分だけ分かるシールを貼っておくとかができますよね。マーキング自体は void * になるので、”alice” という文字列でもよいし、ユニークな数値でも構いません(32,64bit以内であれば)。この手のマーキングは、C# だと GUID として使われているのだろうなぁ、と。