TemplateインターフェースクラスでStrategyパターンを実現する

実装メモ

複数の条件をパスしたレコードだけ抽出するみたいな用途を想定。

#include <iostream>
#include <vector>
#include <string>

/**
 * Template Interface class
 */
template <typename T>
class Filter{
public:
    virtual bool filter(const T &v) const = 0;
    virtual ~Filter(){}
};

/**
 * Templateクラスの継承は親クラスに<>をつける
 */
class LengthFilter : public Filter<std::string> {
public:
    virtual bool filter(const std::string &v) const {
        std::cout << "LengthFilter:4" << std::endl;
        return v.length() > 4;
    }
};

/**
 * コンストラクタ、メンバ変数をもてるのは通常のclassと変わらない
 */
class StringFilter : public Filter<std::string>{
    const std::string matcher;
public:
    StringFilter(const std::string &s) : matcher(s){}

    virtual bool filter(const std::string &v) const {
        std::cout << "StringFilter:" << matcher << ", target:" << v << std::endl;
        return v == matcher;
    }
};

/**
 * 異なる型を具体化した継承
 */
class IntegerFilter : public Filter<int> {
public:
    virtual bool filter(const int &i) const {
        std::cout << "IntegerFilter:4" << std::endl;
        return i > 4;
    }
};

int main() {
    // std::stringで具体化した子クラスを格納するコンテナ
    std::vector<std::shared_ptr<Filter<std::string> > > filters;

    // 型パラメータが同一なら同じコンテナに入れられる
    filters.emplace_back(new LengthFilter());
    filters.emplace_back(new StringFilter("Hoge"));
    filters.emplace_back(new StringFilter("Hello"));

    // 型パラメータが異なればコンパイルエラー
    //filters.emplace_back(new IntegerFilter());

    std::vector<std::string> v;
    v.push_back("Hello");
    v.push_back("Hoge");
    for(const auto &s : v){
        std::cout << "target :"<< s << std::endl;
        for(const auto &f : filters) {
            // 異なるFilterクラスをそれぞれ適用する処理
            if (f->filter(s)) {
                std::cout << "*** Match   ***" << std::endl;
            } else {
                std::cout << "*** Unmatch ***" << std::endl;
            }
        }
        std::cout << std::endl;
    }
    return 0;
}