1

いくつかのタイプの要素があり、それらのすべてのタイプに対して「マネージャー」を作成したいとします。マネージャーは、要素の作成、アクティブ化/非アクティブ化、および削除を処理します(ユーザーは、マネージャーを使用せずにこれらの要素のインスタンスを作成/破棄しないと想定しています。コードの非常に単純な例は、次のようになります。 :

template <class T>
class NonCachedElementMngr
{
public:
    NonCachedElementMngr():
        rmCounter(0)
    {}

    ~ NonCachedElementMngr()
    {
        T* element = 0;
        if(mElements.size() > 0)
        {
            typename std::set<T*>::iterator it;
            for(it = mElements.begin(); it != mElements.end(); ++it)
            {
                element = *it;
                element->deactivate();
                delete element;
            }
        }
    }

    T* create()
    {
        T* element = new T();
        element->activate();
        mElements.insert(element);
        return element;
    }

    bool release(T* element)
    {
        bool ret = false;
        typename std::set<T*>::iterator it;
        it = mElements.find(element);
        if(it != mElements.end())
        {
            element->deactivate();
            delete element;
            mElements.erase(it);
            ret = true;
        }
        return ret;
    }

private:

    std::set<T*> mElements;
    int rmCounter;
};

ここで、オブジェクトのサブグループについて、基本的な操作とは別に、いくつかのキャッシュも行う必要があると想像してみましょう。そのタイプのサブグループに対して、次のような別の「マネージャー」を定義できます。

template <class T>
class CachedElementMngr
{
public:
    CachedElementMngr():
        rmCounter(0)
    {}

    ~CachedElementMngr()
    {
        T* element = 0;
        if(mElements.size() > 0)
        {
            typename std::set<T*>::iterator it;
            for(it = mElements.begin(); it != mElements.end(); ++it)
            {
                element = *it;
                element->removeFromCache();  // <<<<<<<<<<<<<< Different line
                element->deactivate();
                delete element;
            }
        }
    }

    T* create()
            {
        T* element = new T();
        element->storeInCache(); // <<<<<<<<<<<<<< Different line
        element->activate();
        mElements.insert(element);
        return element;
            }

    bool release(T* element)
    {
        bool ret = false;
        typename std::set<T*>::iterator it;
        it = mElements.find(element);
        if(it != mElements.end())
        {
            element->removeFromCache();  // <<<<<<<<<<<<<< Different line
            element->deactivate();
            delete element;
            mElements.erase(it);
            ret = true;
        }
        return ret;
    }

private:

    std::set<T*> mElements;
    int rmCounter;
};

明らかなように、そのようにマークされた3行を除いて、両方のマネージャーはまったく同じです。この2つのテンプレートをリファクタリングするにはどうすればよいですか?コンパイル時に、特定のタイプがキャッシュ可能かどうかがわかります。デストラクタにも別の行があることに注意してください。実行可能な提案(仮想継承、テンプレートの特殊化、SFINAE ...)は大歓迎です。

4

4 に答える 4

2

その特定の動作をポリシーに織り込みます。

#include <set>

struct cached_tag;
struct noncached_tag;

template<typename Tag>
struct ElementMngrCachePolicy;

template<>
struct ElementMngrCachePolicy<cached_tag>
{
    template<typename T>
    static void removeFromCache(T* const element) { /*impl...*/ }

    template<typename T>
    static void storeInCache(T* const element) { /*impl...*/ }
};

template<>
struct ElementMngrCachePolicy<noncached_tag>
{
    template<typename T>
    static void removeFromCache(T* const) { /*do nothing*/ }

    template<typename T>
    static void storeInCache(T* const) { /*do nothing*/ }
};

template<typename T, typename CachePolicy>
class ElementMngr
{
    typedef std::set<T*> elements_t;

public:
    ElementMngr() :
        rmCounter()
    { }

    ~ElementMngr()
    {
        for (typename elements_t::iterator it = mElements.begin(); it != mElements.end(); ++it)
        {
            T* const element = *it;
            CachePolicy::removeFromCache(element);
            element->deactivate();
            delete element;
        }
    }

    T* create()
    {
        T* const element = new T();
        CachePolicy::storeInCache(element);
        element->activate();
        mElements.insert(element);
        return element;
    }

    bool release(T* const element)
    {
        typename elements_t::iterator it = mElements.find(element);
        if (it == mElements.end())
            return false;

        CachePolicy::removeFromCache(element);
        element->deactivate();
        delete element;
        mElements.erase(it);
        return true;
    }

private:
    elements_t mElements;
    int rmCounter;
};

template<typename T>
class CachedElementMngr : public ElementMngr<T, ElementMngrCachePolicy<cached_tag> >
{ };

template<typename T>
class NonCachedElementMngr : public ElementMngr<T, ElementMngrCachePolicy<noncached_tag> >
{ };
于 2011-04-21T08:08:55.727 に答える
1

ポリシークラスを使用します...

template <class T, typename Policy>
class ElementMngr
{
    ~ElementMngr()
    {
        T* element = 0;
        if(mElements.size() > 0)
        {
            typename std::set<T*>::iterator it;
            for(it = mElements.begin(); it != mElements.end(); ++it)
            {
                element = *it;
                Policy::cleanup(element);
                delete element;
            }
        }
    }

    T* create()
            {
        T* element = new T();
        Policy::init(element);
        mElements.insert(element);
        return element;
            }

    bool release(T* element)
    {
        bool ret = false;
        typename std::set<T*>::iterator it;
        it = mElements.find(element);
        if(it != mElements.end())
        {
            Policy::release(element);
            delete element;
            mElements.erase(it);
            ret = true;
        }
        return ret;
    }
};

init()次に、メソッドcleanup()とメソッドの両方を実装する2つのポリシーを定義しますrelease()が、一方は余分な行を実行し、もう一方は実行しません...

編集:実際のコードに似たものになるように擬似コードを修正しました。Policy依存させることができることを示したいと思いTました。たとえば、特定Tの特殊化を使用するか、そうする必要はありません。定義方法を決定できます。ポリシー....

于 2011-04-21T08:05:45.570 に答える
0

オプションはいくつもありますが、基本的な考え方はポリモーフィズムを追加することです。

ランタイムポリモーフィズムの場合、次の一般的な選択肢があります。

  • 戦略パターン
  • キャッシュを使用するかどうかを定義するファンクターを格納します(つまり、std::functionsを使用)
  • テンプレートメソッド(C ++テンプレートとは関係ありません)

Nimの回答で詳しく説明されているように、コンパイル時のポリモーフィズムを使用することもできます。

例として、テンプレートメソッドを次に示します。

template <typename T>
class ElementManager
{
    std::set<T*> mElements;
    int rmCounter;
    virtual void CacheStore(T& element) = 0;
    virtual void CacheRemove(T& element) = 0;
public:
    ElementManager():
        rmCounter(0)
    {}

    ~ElementManager()
    {
        T* element = 0;
        if(mElements.size() > 0)
        {
            typename std::set<T*>::iterator it;
            for(it = mElements.begin(); it != mElements.end(); ++it)
            {
                element = *it;
                CacheRemove(element);
                element->deactivate();
                delete element;
            }
        }
    }

    T* create()
            {
        T* element = new T();
        CacheStore(element);
        element->activate();
        mElements.insert(element);
        return element;
            }

    bool release(T* element)
    {
        bool ret = false;
        typename std::set<T*>::iterator it;
        it = mElements.find(element);
        if(it != mElements.end())
        {
            CacheRemove(element);
            element->deactivate();
            delete element;
            mElements.erase(it);
            ret = true;
        }
        return ret;
    }
}

template <class T>
class CachedElementMngr : public ElementManager<T>
{
    virtual void CacheStore(T& element)
    {
        element->storeInCache();
    }

    virtual void CacheRemove(T& element)
    {
        element->removeFromCache();
    }
};

template <class T>
class NonCachedElementMngr : public ElementManager<T>
{
    virtual void CacheStore(T& element)
    {
        //Purposely Empty
    }

    virtual void CacheRemove(T& element)
    {
        //Purposely Empty
    }
};
于 2011-04-21T08:05:19.770 に答える
0

具体的には、例から、上記の3行class CachedElementMngrを除くすべての機能が完全に含まれているようです。class NonCachedElementMngr私はこのようなことをします:

template<typename T>
class NonCachedElementMngr
{
  /* put all content of "CachedElementMngr" in your example and below methods */
  virtual void removeFromCache(T* p) { /* empty */ }
  virtual void storeInCache(T* p) { /* empty */ }
  virtual ~NonCachedElementMngr() { /*retain original */ }
};

template<typename T>
class CachedElementMngr : public NonCachedElementMngr<T>
{
// everything is inherited; just add below methods in this class
  virtual void removeFromCache(T* p) { p->removeFromCache(); }
  virtual void storeInCache(T* p) { p->storeInCache(); }
  virtual ~CachedElementMngr() { /*retain original */ }
};

そして、次のメソッドを次のように呼び出すのではなく、

p->removeFromCache();
p->storeInCache();

それは次のように呼ばれるべきです

removeFromCache(p);
storeInCache(p);
于 2011-04-21T08:34:34.980 に答える