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

Adapter
  〜変換コネクタパターンです


 Adapterパターンは別名Wrapperパターンとも呼ばれます。ラッパー、つまり「包む」という意味です。あるクラスに適合するように、他のクラスを包み隠す構造にするのがAdapterパターンです。このパターンは、他の人が作ったクラスを自分のクラスに合わせる時などに多用されます。それは、変換コネクタで別のクラスを自分のクラスに変換するかのような振る舞いです。

 サウンドノベルスなどでは、絵を表示させる位置を取得する仕事があります。位置は画面に出るオブジェクトすべてに共通するでしょうから、これを親クラスとします。

class ObjPos
{
protected:
   int m_x;   // 横位置
   int m_y;   // 縦位置

public:
   void GetPos(int *x, int*y){
      *x = m_x;
      *y = m_y;
   }
};
class PictPos : public ObjPos
{
protected:
   BITMAP n_BMP;
};


 ところでノベルスには、30文字×10行といった「テキストを整える」という仕事もまた必要になります。ある人が作ったクラスでは、整形した結果、その位置を取得できるとしましょう。

class TextAline
{
protected:
   int m_TextLeft;   // テキストの左端位置
   int m_TextTop;   // テキストの右端位置
   string m_text;

public:
   int GetLeft(){return m_TextLeft;}
   int GetTop;(){return m_TextTop;}
   void SetText(char* text);
};

 とても便利なクラスなのですが、変数関数とも先のクラスとまったく互換性がありません。AdapterパターンはこのTextAlineクラスをObjPosクラスに適合させる試みをします。

 Adapterパターンには2つの方法があります。1つは「クラスを多重継承する」、もう1つは「コンポジションとしてオブジェクトを持つ」方法です。
 クラスの多重継承というのは、次のようにクラスを派生させます。


 自分が作成したクラスに新しくTexPosという派生クラスを設けるのですが、この時他人が作成したTextAlineクラスも継承します。そして、GetPos関数でTextAlineクラスのメンバ変数を借りてしまいます。こうすることで、TextAlineの機能を受け継いで、かつGetPos関数もちゃんと使用できるオリジナルクラスができます。

 一方、コンポジションとしてオブジェクトを保持する方法は、次のとおりです。


どこが変わったかわかりますでしょうか?TextPosからTextAlineクラスに伸びる矢印が継承ではなく「関係」になっています。TextPosの内部にTextAline型のtexinfo変数を定義し、内部で情報を利用しています。

 どちらの方法でも、他人のクラスの機能を自分のクラスの機能に変換しています。クラスの多重継承の方は、コンパイル時に型が決定されるので簡単ですが、TextAlineクラスのメンバ関数が公開されてしまいます(praivate宣言で多重継承すると良いかもしれません)。コンポジションとしてオブジェクトを保持する方法は、ポインタとして保持することによりTextAlineのサブクラスも持つことが可能ですし、TextAlineクラスの機能は完全に隠蔽できます。しかし、TextAlineオブジェクトを生成する仕事が必要です。
 どちらにするかはこれらのトレードオフを考慮して決定するべきですが、コンポジションの方が利点が多いように感じます。