いよいよデザインパターンのジェネリックな実装です。 テンプレートメタプログラミングによって再利用可能な設計を実装する、 とかいうジャンルですね。 設計を実装するなんて、なんとも矛盾した響きなのですが。
内部実装は結構いっちゃってますが、 外身を見るだけならGoFを読んでればまあ、余裕です。
私は残念ながら AbstractFactory パターンを使うのが適する 複数の継承ツリーを差しかえる場面に出逢ったことが無いのですが、 まあ、AbstractFactory パターンを使うべき場面なのであれば これが凄く役に立つことが容易に想像できます。
では、使用例。本の利用法のそのまんまですが…
class Soldier { public: virtual void what() const =0; }; class EasySoldier : public Soldier { public: virtual void what() const { std::cout << "EasySoldier" << std::endl; } }; class NormalSoldier : public Soldier { public: virtual void what() const { std::cout << "NormalSoldier" << std::endl; } }; class Monster { public: virtual void what() const =0; }; class EasyMonster : public Monster { public: virtual void what() const { std::cout << "EasyMonster" << std::endl; } }; class NormalMonster : public Monster { public: virtual void what() const { std::cout << "NormalMonster" << std::endl; } };
GoFを知っていればすぐに AbstractFactory が欲しくなる局面です。 JavaプログラマならGoFを片手に設計の再利用にかかるところですが、 我等が c++ & Loki では…
typedef Loki::AbstractFactory< TYPELIST_2(Soldier, Monster)> AbstractEnemyFactory; typedef Loki::ConcreteFactory< AbstractEnemyFactory, Loki::OpNewFactoryUnit, TYPELIST_2(EasySoldier, EasyMonster) > EasyFactory; typedef Loki::ConcreteFactory< AbstractEnemyFactory, Loki::OpNewFactoryUnit, TYPELIST_2(NormalSoldier, NormalMonster) > NormalFactory;
実装も再利用できます。これでおしまい。とても簡単。
それで、使いかたは…
{ std::auto_ptr<AbstractEnemyFactory> factory(new EasyFactory); // ここから下は同じコード std::auto_ptr<Soldier> soldier(factory->Create<Soldier>()); std::auto_ptr<Monster> monster(factory->Create<Monster>()); soldier->what(); monster->what(); } { std::auto_ptr<AbstractEnemyFactory> factory(new NormalFactory); // ここから下は同じコード std::auto_ptr<Soldier> soldier(factory->Create<Soldier>()); std::auto_ptr<Monster> monster(factory->Create<Monster>()); soldier->what(); monster->what(); }
こんな感じです。最初に Easy なり Normal なりを決定してしまえば、 後は何も考えずに factory->Create しとけば良いのです。
全てリンクフリーです。 コード片は自由に使用していただいて構いません。 その他のものはGPL扱いであればあらゆる使用に関して文句は言いません。 なにかあれば下記メールアドレスへ。