Strategyパターンの実装

非スタティックなメンバ関数ポインタを使う方法を試してみた。

main.hpp

#include <boost/lambda/bind.hpp>
#include <boost/function.hpp>
#include <iostream>

class CSample
{
public:
    void fSetFunc(int Index);
    void fFunc1(){std::cout << "fFunc1" << std::endl;}
    void fFunc2(){std::cout << "fFunc2" << std::endl;}
    void fFunc();
    void (CSample::*mpFunc)();  /* 普通のメンバ関数ポインタ */
    boost::function<void (CSample*)> boost_func; /* boost::function */
    boost::function<void ()> boost_bind_func; /* boost::functionとbind */
};

main.cpp

#include "main.hpp"

int main()
{
    CSample Sample;
    Sample.fSetFunc(1);
    Sample.fFunc();
    Sample.fSetFunc(2);
    Sample.fFunc();
	return 0;
}

void CSample::fSetFunc(int Index)
{
    switch (Index) {
    case 1:
        mpFunc = &CSample::fFunc1;
        boost_func = &CSample::fFunc1;
        boost_bind_func = boost::lambda::bind(&CSample::fFunc1,this);
        break;
    case 2:
        mpFunc = &CSample::fFunc2;
        boost_func = &CSample::fFunc2;
        boost_bind_func = boost::lambda::bind(&CSample::fFunc2,this);
        break;
    default:assert(false);break;
    }
}

void CSample::fFunc()
{
    (this->*mpFunc)();
    boost_func(this);
    boost_bind_func();
}

これクラスを作るより手軽でいいなぁ。というか、これをStrategyパターンと言ってしまっていいのか疑問だけど。Effective C++を見る限りStrategyパターンの一種みたい。

利点と欠点を考えてみる。

  • コンポジションと継承を使ったStrategyパターン
    • クラスと派生クラスを作るので実装が面倒
    • privateメンバにアクセスしたい場合はアクセサの追加や、friend登録が必要。
    • クラスにメンバ変数として状態を持たせることができる。
  • メンバ関数ポインタによるStrategyパターン
    • メンバ関数なので、privateメンバにもそのままアクセスできる。
    • クラスを作らないので実装が手軽。

Strategy特有の状態を保持したいかしたくないか、で決めるのが良さそうだ。途中で状態を持たせたくなった場合に直すのが面倒そうなのが懸念点か。