ホーム < ゲームつくろー! < デザインパターン習得編

Abstract Factory
  〜 一塊のオブジェクト群を沢山の種類用意する


@ こんなオブジェクト生成はしてはいけない

 STGの自機は「Weapon」「Bomb」と、オブジェクトがセットである事が多いと思います。このとき、Macineオブジェクトにこれらを設定しようと、次のようなCreate関数を設けたとします。

class Macine
{
private:
   Weapon *m_Weapon;   // ウェポンオブジェクトへのポインタ
   Bomb *m_Bomb;      // ボムオブジェクトへのポインタ

public:
   void Create()
   {
      m_Weapon = new Weapon;
      m_Bomb = new Bomb;
   }
};


 これは、設計として非常にまずいです。m_Weaponやm_Bombが固定したオブジェクト(Weapon、Bomb)になってしまい、柔軟性ゼロです。そこで、例えば次のような設計を次に考えます。

void Macine::Create(Weapon *wp, Bomb *bm)
{
   m_Weapon = wp;
   m_Bomb = bm;
}

 これは、外部でWeaponオブジェクトとBombオブジェクトを生成して、それをMacineオブジェクトのメンバ変数に渡している形になっています。Weaponクラスを派生させてSpecialWeaponクラスを作った場合、それを親クラスとして引数に渡す事ができます。これで、武器の選択ができるようになりました。

 しかし、例えば武器やボムをMacineクラス自体が選択したい事があります。例えば、Macineクラスの派生クラスType1Macineで、ShotGunWeaponとNapalmBombを使う事がわかっているなら、オブジェクト内部で作ってもらった方が、外部の人は渡すべき武器について知らなくて良いので楽になります。


A Abstract Factoryによるオブジェクト生成

 Abustact Factroyパターンは、このような「あるオブジェクトが沢山のオブジェクトの塊を持ちたい」時に使えます。Abstract(抽象的な)Factory(工場)ですから、「WeaponとBombを持て」という抽象的な塊に対して使えます。まず、次のようなクラスを作ります。

class AbstractWeapons
{
public:
   virtual Weapon* CreateWeapon(int code) = 0;
   virtual Bomb* CreateBomb(int code) = 0;
};


class AbstractWeaponsType1 : public AbstractWeapons
{
public:
   virtual Weapon* CreateWeapon() {
      return new Weapon;
   }
   virtual Bomb* CreateBomb() {
      return new Bomb;
   }
};

 AbstractWeaponsクラスは純粋仮想関数で定義されています。実装は派生クラスであるAbstractWeaponsType1クラスで行います。この派生クラスはType1武器の組である「WeaponとBomb」のオブジェクトを返してくれます。
 さきほどのType1Macineクラスを次のように再設計します。

class Type1Macine
{
private:
   Weapon *m_Weapon;   // ウェポンオブジェクトへのポインタ
   Bomb *m_Bomb;      // ボムオブジェクトへのポインタ

public:
   void Create( AbstractWeapons *AbsWep )
   {
      m_Weapon = AbsWep->CreateWeapon();
      m_Bomb = AbsWep->CreateBomb();
   }
};

 Create関数に生成専用のクラスを渡し、内部オブジェクトをファクトリクラスからもらっています。呼び出し側との連携は次のようになります。

Type1Macine Myship_T1;
AbstractWeaponsType1 AbsWepT1;

MyshipT1.Create( &AbsWepT1 );


 Type1Macineオブジェクトを生成し、武器を生成するファクトリクラスを作成し、「武器を設定しなさい」と命令します。AbstractWeaponsType1クラスを変更したとしても、この呼び出し側のプログラムはまったく変わりません。これがポイントです。Type1の自機がどういう武器を生成するか、呼び出し側はもう考えなくてよくなります。


Abstract Factoryの一般図は次のようになります。


同じ図式でSTGの自機の例を示します。



B こんなときにはAbstract Factory

 Abstract Factoryは、沢山のオブジェクトで構成される「固定的な」オブジェクトを生成するときに利用すると便利です。例えば、RPGに出てくる主人公クラスのキャラクターについて、「剣」「鎧」「兜」「盾」というオブジェクトの組み合わせで「武具」が構成されるとき、これらをAbstract Factoryでまとめておくと、別のキャラクタにはそれようのクラスを作れば独自のキャラクタをどんどん作成できます。

 Windows Media Playerなどアプリケーションを着飾る「スキン」にはAbstract Factoryが使えます。スキンは、「外枠」「再生ボタン」「停止ボタン」など画面を構成する部品が厳格に決まっているので、Abstract Factoryが使いやすいでしょう。


C こんなときに適用は難しい

 Abstract Factoryは、構成オブジェクトの種類が増減するオブジェクトへは適用しにくいかと思います。さきほどの「武具」について、新しく「ガントレット」を追加したいと考えて、Abstract Factoryクラスへそれを追加した場合、派生するクラスすべてを更新する必要が出てきます。そういう追加を行う場合、元のクラスを変更するのではなく、ガントレットは別のAbstract Factoryクラスとして定義して使用するしかないでしょう。