FlyWeight

ついでにFlyweight。いやぁ、馴染み深いコトバです。なぜなら僕がフライ級ボクサーだからですが…そんなことはどーでもいい。

えーと、まぁメモリとかロード時間とかいろいろ節約するためのパターン。もう適当な実装書いたほうが早いんで書きます。
#include<map>
using namespace std;

class Loader
{
private:
  map<string,char*> m_map;
public:
  void* load(string filename)
  {
   map<string,char*>::iterator it = m_map.find(filename);
   if( it != m_map.end() ){//既にロード済
    return it->second;//ロードせずポインタを返す
   }
   else{//新規ロード
    fopenだのなんだの...
    char* buf = freadだのなんだの...
    m_map.insert(make_pair(filename,buf) );//新規データを登録
    return buf;
   }
  }
};

…まぁサンプルなんで解放とかの問題なんて気にすんな!要は上のようにして余計なメモリやファイルアクセスをしないようにするってことだね!!ただこのままだとどんどんたまっていってバッドアロック例外になるはずなんで、それは各自考えてくれ!!まぁ参照カウンタつきスマートポインタでも実装してくれたまえ。

それができる人はFlyweightくらい知ってるって?まぁ、そうかもね。この実装だとマップから削除するタイミングが意外と難しいんじゃないかな。上の例ではナマポインタだけど、IsAliveだのIsValidだのチェックできるようにして、毎フレ削除更新かけるのもありだと思うけど。

| | コメント (0) | トラックバック (0)

Abstruct Factory

はい、今日は先生がAbstruct Factoryについて解説するぞー。

簡単に言います。「アブストラクトファクトリ」は「ファクトリ」を切り替え可能にするためのパターンです。

…言っちゃった。

ファクトリはわかりますよね?わかんねぇ?例えば、C++で適当に書くなら

class IBase
{
public:
  virutal void tekitou()=0;
};

class Derive1 : public IBase
{
public:
  virutal void tekitou()
  {
   cout << "A";
  }
};

class Derive2 : public IBase
{
public:
  virutal void tekitou()
  {
   cout << "B";
  }
};

とかやって、

class Factory
{
public:
  IBase* create(int param)
  {
   if(param){
    return new Derive1();
   }
   else{
    return new Derive2();
   }
  }
};

で、

Factory f;
IBase* b = f.create(0);
b.tekitou();
IBase* c = f.create(1);
c.tekitou();

てな感じ。どっちもIBase型なのに、振舞いがかわるんだねぇ。むむっ、仕事が忙しくて少しだけボクサーにあるまじきお腹になっている!!ちょっと腹筋200回します。

…ハァハァ、プログラマとボクサーの両立は大変ですたい。

あ、まだAbstruct Factoryじゃないですよ。ここまでは通常のC++のテクニック、Factory Methodではあるけれど、まぁわざわざパターンって呼ぶまでもないのねん。で、ここからがAbstruct Factory

その名の通り、ファクトリクラスをAbstructにします。つまり

class IFactory
{
public:
  vitrual IBase* create(int param)=0;
};

class IFactory
{
public:
  vitrual IBase* create(int param)=0;
};

class Factory1 : public IFactory
{
public:
  vitrual IBase* create(int param)
  {
   if(param){
    return new Derive1();
   }
   else{
    return new Derive2();
   }
  }
};

class Factory2 : public IFactory
{
public:
  vitrual IBase* create(int param)
  {
   if(param){
    return new Derive3();
   }
   else{
    return new Derive4();
   }
  }
};

と、なります。で、これを例えばシステムに組み込むとすれば

class System
{
private:
  IFactory* m_factory;
public:
  void SetWindowFactory(IFactory* factory){
   m_factory = factory;
  }
  void createWindow(int param){
   m_factory.create(param);
  }
};

System s;
s.SetWindowFactory(new Factory2);
s.createWindow(1);

てな使い方ができる。つまりファクトリ自体の振舞いが変わるってわけ。そんなことして何の利点があるん?というとですな。まぁ、場面によって生成されるものの性質を大きく変えたいとか、マルチプラットフォーム時のためとか、アロケータだのローダーの生成方法を変えたいときに使用する。

ここでの例のように生成されるウィンドウの種別を変えてもいいけどね(GOF本の解説ではそういう用途だった)。

| | コメント (0) | トラックバック (0)

テンプレート1

ModernC++Designをだいぶ理解できてきました。これというのもウチのプログラマボスのおかげです。いやー
昨年までテンプレートのテの字もわかんなかった僕が…。タイプリストまで理解しました。ていうかタイプリスト
の発想のすごさに脱帽。
テンプレートを再帰させるなんて…普通考えつかないって。
まあ、昔どこかでコンパイル時に「フィボナッチ数列」の計算を行うサンプルを見たので、それを考えれば
不可能ではないのかもしれないけどとにかくすごい。

複数の型を持つテンプレートクラスの作り方は普通

template<typename T1,typename T2>
struct Foo
{
    T1 t1;
    T2 t2;
};

んで特殊化すると

template<typename T1>
struct Foo<T1,double>
{
    T1 t1;
    double t2;
};


template<typename T2>
struct Foo<char,T2>
{
    char t1;
    T2 t2;
};

template<>
struct Foo<char,int>
{
    char t1;
    int t2;
};

ってな感じです。ここまでは僕でもわかります。アンドレイアレキサンドレスク氏のすごいのはここからで

template<typename U , typename L >
struct TypeList
{
    typedef U Head;
    typedef L Tail;
};

アッーーーー!

typedefを使うなんて…。
さらに

typedef TypeList< char , TypeList<int,double> > TripleList;

とすれば、型の並びを表現できます。ただしいちいち書いていくのは面倒なので
次のようなマクロを用意します。

#define TYPELIST_1(T1) TypeList<T1,NullType>
#define TYPELIST_2(T1,T2) TypeList<T1,TYPELIST_1(T2)>
#define TYPELIST_3(T1,T2,T3) TypeList<T1,TYPELIST_2(T2,T3)>

とはいえ、このマクロを書くのも面倒なので、僕はAWK言語を用いて32まで
用意しました。そう、メタプログラミングを他言語を用いて記述!まさにメタメタプログラミング!!

「で、どこで使うのよ」と言われそうなので、一例。
通常可変長引数をとる関数は、それぞれの型がわかりません。

void Sample(...)
{
    ?
}

ところが、タイプリストを一緒に渡してあげれば、順順に方がわかるのですよ。奥さん!
この他の使い方も検証してみるつもりですが、それはもうちょっとModernC++Designを読んでから。
難しいことに変わりはないので…。

| | コメント (0) | トラックバック (0)