工場長直下去勢許可局っ!! (舌噛み | ゲームプログラマ志望が福岡で叫ぶ 『絶望』

ゲームプログラマ志望が福岡で叫ぶ 『絶望』

プログラマーになりたい!!!!! あ、風のうわさで聞いた最近若者で流行っているトゥイッターなるものを始めてみました (・ト・) @toshi_desu_yo

C++ をお勉強していると時たま目撃する Factory という文字。



デザインパータンの一種である彼は、

ただ、 new してオブジェクトを返す。



class Human{};

;// 人間を作る工場
class HumanFactory
{
public:
    Human* CreateInstance()
   {
       return new Human;
   }
};


~~~~~~~~~~~~~~~~~~

HumanFactory* pHumanFactory = new HumanFactory;

// Humanが生成される
Human* pHuman = pHumanFactory->CreateInstance();




↑ Human が new されて戻ってくる。
そして上の例では delete を忘れてしまいそうなので本当はスマートポインタにしたい所。






『なんだそれ?? 
   生成とか自分で new 書いてするし特にいらねーじゃん・・・』


と、ずっと思って使ってなかったのですが、





 『おぉ~!』と思える例がありました。




********************************************


① : 生成コードを分ける。




ゲーム作成時、ある所でモンスターを作りたいとなりました。



識別子によって生成したいモンスターを変えたいです。

現在、モンスター情報クラス自体が生成コードを持つ書き方をしています ↓



// モンスター情報を持つ
class MonsterInfo
{
private:
       Monster* pMonster;

public:
       Monster( MONSTER_TYPE )
       {
           switch( MONSTER_TYPE )
          {
               case SLIME: pMonster = new Slime;
 ・
 ・
 ・ 
          }

       }
};





う~ん・・・
あまり長いコードを1つのクラスに書くのは可読性を殺してしまう・・・




出来れば生成コードは別の所に移したい。。


それにモンスター生成コードだけは別の場所でも使うかも。

そこでまた書くの面倒くっっさ Σ(゚ё゚ノ)ノ 





って時にFactoryクラスを別で作成し、この中でガッシャンガッシャン作っちまいます。



//** モンスターを作成する工場
class MonsterFactory
{
public:
    Monster* CreateInstance( MONSTER_TYPE type )
    {
        Monster* pMonster;
       
        switch( type )
        {
            case FASHION_MONSTER:   pMonster = new FashionMonster;
            case OPPAI_MONSTER:        pMonster = new OppaiMonster;
        };


        return pMonster;
    }
};




なんか、
人間やモンスターを工場で生成するって思うと悲しくなりますねw






これでモンスターの生成を分けることが出来、

ファクトリーに識別子を渡すだけでモンスターが返ってきます。




MonsterFactory* pMonsterFactory = new MonsterFactory;

Monster* pMonster = pMonsterFactory->CreateInstance( FASION_MONSTER );



↑のファクトリーは、
様々なクラスに使用する可能性もあり、使い回しできそうなので

シングルトン化するといいかもしれないです。








② : 色々変化するぜ!


class Human{};


という 人間の元クラスがあり、こいつを継承しているクラスがたくさんあるとします。 


識別子を使わず、生成をその場その場で切り替えたい時。



class Human{};
class Woman : public Human {};
class Gentleman : public Human {};

class HumanFactory
{
public:
    virtual Human* CreateInstance() = 0;
};



という基底ファクトリークラスを作って、


Class WomanFactory : public HumanFactory
{
public:
    virtual Human* CreateInstance() { return new Woman; }
};

Class GentlemanFactory : public HumanFactory
{
public:
    virtual Human* CreateInstance() { return new Gentleman; }
};








~~~~~~~~~~~~~~~~~~~~~~~~

HumanFactory* pHumanFactory = new pWomanFactory();

// 女性が生成される(*´Д`)
Human* pHuman;
pHuman = pHumanFactory->CreateInstance(); 





識別子がないので良い感じ///

しかし、型によってこんなの作っていては使いにくい。 いや、面倒くさい





③ : 柔軟なFactory


型によって作成するのが面倒臭いなら型をなくせばいいじゃ~ん。

そういうことで template を使ってみます。




template < class T >
class Factory
{
public:
    virtual T* CreateInstance() { return new T; }
};




~~~~~~~~~~~~~~

Factory< Woman > pHumanFactory;

Human* pHuman = pHumanFactory.CreateInstance();

↑ Woman インスタンスが作成される。





これで大分Factoryが使いやすくなりました。





④ : 変身




次に、



メタモンがいます。








・・・って、まぁ実際にはいないし、特に意味もないんですがw




何でも変身できるメタモン。 


Object というクラスを継承したクラスに何でもなれるとします。
実際は Objectクラスを内部にもち、使用出来る。。とする。



コンストラクタに変身先の識別子を渡すようにした場合、



class Metamon
{
private:
    OBJECT_TYPE mObjectType;
    Object* mpObject;

public:
    Metamon( OBJECT_TYPE type )
        : mObjectType( type )
    {
        switch( type )
       {
            case TYPE_NAKED_LADY:  mpObject = new NakedLady;
            case TYPE_OPPAI:               mpObject = new Oppai;
    ・
    ・
    ・
       }

    }
}



まぁ、臭い。




そして、後から新たな変身先を追加した場合、

Metamonクラスをいじらなければなりません。



しかし、Metamonクラスをライブラリ化していた場合
Metamonクラスをいじることは不可能になります。




これでは新しく何かを追加したい場合、恐らく現実から逃走します。



なので、
ファクトリークラスを渡すようにします。



class Metamon
{
private:
    Object* mpObject;

    // Object型のFACTORYクラスを内部に持つ
    Factory< Object > mObjectFactory;

public:

    Metamon( Factory< Object >& objectFactory )
        : mObjectFactory( objectFactory )
    {
        // 例ではコンストラクタで生成してるが、
        //  いろいろな場所で生成できる。
        mpObject = objectFactory.CreateInstance();
    }
};




(こんな作りをする人がいるかわかりませんがw)



コレだと自分でファクトリークラスを色々書きなおしてから

渡すだけでそれに変身してくれるので良い感じ、じゃないでしょうか?



Metamonがライブラリ化していても変身先を増やせる。






まぁ、こんな感じに作りたいと思った場合、

コンストラクタで Object を継承したクラスのtemplateファクトリークラスを渡したいです。



// Objectを継承したクラス。
class Oppai : public Object
{};




// Oppaiに変身して欲しいからOppai型のFactoryを作成
Factory< Oppai > objectFactory;

// こんなかんじに渡すのかな?
Metamon* pMetamon = new MetamonobjectFactory );






しかし、これはエラーが出ます。




Oppaiが Object を継承しているとはいえ、

 Factory< Oppai > Factory< Object > の間にはなんの継承関係もないのでダメです。





なので新たなファクトリクラス。。


// T が基底クラス。 S は Tを継承したクラス。
template < class T, class S >
class SecondFactory : Factory< T >  // Factory< T >を継承している
{
public:
        // SをTに変換して返す
        virtual T* CreateInstance() { return new S; }
};



を作ってみる。






こうすれば、


// Object と、それを継承した Oppai を template に渡す
SecondFactory < Object, Oppai > objectFactory;

// Oppaiに変身するメタモン
Metamon* pMetamon = new Metamon( objectFactory );






と、

引数のファクトリークラス( SecondFactory< T, S >)メタモン内にあるファクトリークラス( Factory< T > )


継承関係にあるのでエラーは出ません。



かつ、 Metamon内で ファクトリーを使うと Oppai クラスが生成されます。





なんか当たり前のようですが、ファクトリーの有用性がわかった気がしました。







こんなかんじに、


 後から、生成したいクラスを増やす or 変えたい!


という時にすごい便利です。






たとえば、
上記に加えてメタモンにお金にも変身して欲しい時

Factory クラスを新たに 




class Money : public Object
{};




そして 新たなFactory...

SecondFactory < Object, Money > objectFactory;

と作れば、

~~~~~~~~~~~~~~

// お金に変身するメタモン
Metamon* pMetamon = new Metamon( 
objectFactory );




メタモンはお金に変身します。  


お金ほしいわー・・・

(´;ω;`)







*******************************



これまで、Factoryを使って来なかったので、コレを踏まえて僕も





Factoryをまな板の鯉のように、踊るように使ってゲームを作成してみたいです( - ω - )






↑の SeconFactory は、もっと使いやすく出来ます。

一々コンストラクタに引数で渡してるあたりを消して、、、
デフォルトでは Oppai を生成ようにする。 指定があれば生成するObjectを変化させる。



という風にしたいです( ゚ρ゚ )





Windowsプロフェッショナルプログラミングという本に
完全実装が載っております。

C++ を初めて『そろそろ新しいこと覚えたいなぁ~・・・』 

となってる方に是非進めたい一品でございまする。



中古ではものすっごやすいですw

中古といえど、僕のは新品同様でした。CDも未開封でしたし..

Windowsプロフェッショナルゲームプログラミング/秀和システム
¥2,940
Amazon.co.jp



以上!


 仕事頑張る