続・続・ interface と実装を分離する

長いんだけど http://d.hatena.ne.jp/janus_wel/20100608/1275989229 の最後で言ってた interface の管理用 class の実装例を書いてみた。長くなったついでに複数の似たような object を管理できるようにもしてみた。以下の code では id という整数値を指定して object への参照を得ているけど unique な値の集合であればなんでもいいので例えば file の絶対 path やら MD5 やらに応用が可能なはず。

// interface.hpp

#ifndef INTERFACE_HPP
#define INTERFACE_HPP

#include <string>

namespace sample {
    struct interface_type {
        virtual void print(void) const = 0;
        virtual void set(const std::string& str) = 0;
    };

    struct controler_type {
        virtual interface_type& use(int id) = 0;
        virtual void release(const interface_type& target) = 0;
    };

    // Returning reference
    controler_type& controler(void);
}

#endif // INTERFACE_HPP
// implement.cpp

#include "interface.hpp"

#include <algorithm>
#include <functional>
#include <iostream>
#include <list>

#include "../../../github/cpplib/header/algorithm.hpp"

namespace sample {
    namespace implement {
        class concrete_type : public interface_type {
            private:
                const int mv_id;
                std::string mv_str;

            public:
                concrete_type(int id) : mv_id(id), mv_str("concrete") {
                    std::cout << "concrete_type(" << mv_id << ")" << std::endl;
                }
                ~concrete_type(void) {
                    std::cout << "~concrete_type(" << mv_id << ")" << std::endl;
                }
                void print(void) const {
                    std::cout << mv_str << std::endl;
                }
                void set(const std::string& str) {
                    mv_str = str;
                }
                const bool is_me(int id) const { return mv_id == id; }

            public:
                bool operator==(const concrete_type& rhs) {
                    return mv_id == rhs.mv_id;
                }
                bool operator!=(const concrete_type& rhs) {
                    return !(*this == rhs);
                }

            private:
                concrete_type& operator=(const concrete_type&);
        };

        class ccontroler_type : public controler_type {
            private:
                typedef std::list<concrete_type*> concrete_array_type;

            private:
                concrete_array_type concrete_array;

            public:
                ~ccontroler_type(void) {
                    std::for_each(
                            concrete_array.rbegin(), concrete_array.rend(),
                            util::algorithm::sweeper());
                }

                interface_type& use(int id) {
                    concrete_array_type::iterator found =
                        std::find_if(
                                concrete_array.begin(), concrete_array.end(),
                                std::bind2nd(std::mem_fun(
                                    &sample::implement::concrete_type::is_me
                                    ), id));

                    // found
                    if (found != concrete_array.end()) return **found;

                    // not found and create
                    concrete_type* created = new implement::concrete_type(id);
                    concrete_array.push_back(created);
                    return *created;
                }

                void release(const interface_type& target) {
                    concrete_array_type::iterator found =
                        std::find(
                                concrete_array.begin(), concrete_array.end(),
                                &target);

                    if (found != concrete_array.end()) {
                        delete *found;
                        concrete_array.erase(found);
                    }
                }
        };
    }

    controler_type& controler(void) {
        static implement::ccontroler_type controler;
        return controler;
    }
}
// main.cpp

#include "interface.hpp"

using namespace sample;

int main(void) {
    interface_type& i01 = controler().use(1);
    i01.set("one");
    i01.print();

    interface_type& i02 = controler().use(2);
    i02.set("two");
    i02.print();

    controler().release(i01);

    interface_type& i03 = controler().use(3);
    i03.set("three");
    i03.print();

    interface_type& i04 = controler().use(2);
    i04.set("four");
    i04.print();

    return 0;
}