いよいよデザインパターンのジェネリックな実装です。 テンプレートメタプログラミングによって再利用可能な設計を実装する、 とかいうジャンルですね。 設計を実装するなんて、なんとも矛盾した響きなのですが。
内部実装は結構いっちゃってますが、 外身を見るだけなら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扱いであればあらゆる使用に関して文句は言いません。 なにかあれば下記メールアドレスへ。