шаблон стратегии - PullRequest
       1

шаблон стратегии

2 голосов
/ 11 июня 2010

Я хочу разделить класс так, чтобы он был отделен от логики выполнения определенной задачи, чтобы пользователи могли писать новые стратегии по своему усмотрению, не мешая центральной модели. Итак, я хочу использовать шаблонный класс стратегии, но не нужно, чтобы пользователь стратегии был шаблонизирован:

   class Model {  
     ...  
     boost::shared_ptr< Strategy < T > > m_pStrategy;  
     ...  
     public:  
     template <  typename T  >  
     void DoSomething() { m_pStrategy < T > ::DoSomething(); }  
    };  

Я бы хотел, чтобы функция DoSomething не была шаблонной. Есть ли другой способ добиться того, что я хочу здесь сделать?

спасибо.

Ответы [ 2 ]

7 голосов
/ 11 июня 2010

Мне кажется, что вы хотите реализовать Дизайн на основе политик . Я не уверен, что именно Model и Strategy делают точно, но кажется, что Model - это корневой класс, а Strategy - это класс Policy, который пользователи в некоторых случаях хотели бы предоставить для выполнения специальной обработки. , Также кажется, что единственная причина, по которой вы держите указатель на объект Strategy<T>, заключается в том, что вы можете вызывать функции для него.

В этом случае вы можете создать свой класс следующим образом:

template<class Strategy> 
class Model : public Strategy {  
 public:  
 void DoSomething() 
 { 
    // magic happens (we will fill this in shortly)
 };
};  

Вы вызываете методы класса Strategy, чтобы творить чудеса. Позволяя пользователям определять свой собственный класс Strategy, вы даете им возможность определять свою собственную «магию». Вам необходимо применить правила к тому, какой метод класс Strategy предоставит как минимум, чтобы вы могли вызывать эти методы в Model.

Например, предположим, что Model на самом деле является неким менеджером ресурсов, способным быть простым умным указателем, или чем-то другим, похожим на менеджер ресурсов для критической секции Windows. Давайте переименуем Model в auto_resource, и Strategy станет release_policy и будет отвечать за освобождение любого ресурса, который был ему назначен. В этом случае вы можете иметь:

class pointer_release_policy
{
public:
  template<class Object> void release(Object* obj) { delete obj; }  
};

template<class Managed, class release_policy>
class auto_resource : public release_policy
{
public:
  // ... ctors etc defined here
  ~auto_resource()
  {
    release_policy::release(managed_);
  }
private:
  Managed managed_;
};

Что вы можете использовать для std::string указателей, таких как:

typedef auto_resource<std::string*, pointer_release_policy> string_ptr;
string_ptr my_str;

... и когда my_str падает со стека, автоматически вызывается метод release.

Позже вы захотите добавить новую политику для освобождения мьютекса Windows HANDLE s:

class handle_release_policy
{
public:
  template<class Handle> void release(Handle h)
  { 
    CloseHandle(h); // this is a WINAPI function that deallocates the specified resource
  };
};

Вы можете использовать это так:

typedef auto_resource<HANDLE, handle_resource_policy> handle_resource;
//... allocate & use the mutex...
handle_resource mutex = CreateMutex(0, 0, 0);

Конечно, для того, чтобы конкретизировать все это, вам нужно добавить функциональность для назначения, копирования, освобождения и т. Д. Ресурсов. Вот полный рабочий пример, который собирает все вместе. Я предоставил 2 набора политик, один для Windows CRITICAL_SECTION s, а другой для SOCKET s:

class SimpleCopyPolicy
{
public:
    template<class Resource> Resource copy(const Resource& rhs) const { Resource ret = rhs; return ret; }
protected:
    ~SimpleCopyPolicy(){};
};

class CritsecReleasePolicy
{
public:
    template<class Handle> bool release(Handle& h)
    {
        DeleteCriticalSection(&h);
        return true;
    }
protected:
    ~CritsecReleasePolicy() {};
};

class CritsecLockPolicy  // CRITICAL_SECTION lock/unlock policies
{
public:
    template<class Handle> bool lock(Handle& h)
    {
        EnterCriticalSection(const_cast<CRITICAL_SECTION*>(&h));
        return true;
    }
    template<class Handle> bool unlock(Handle& h) 
    {
        LeaveCriticalSection(&h);
        return true;
    }
};


class SocketReleasePolicy
{
public:
    template<class Handle> bool release(Handle h) { return 0 != closesocket(h); }
protected:
    ~SocketReleasePolicy(){};
};

template<class Resource, typename ReleasePolicy, typename CopyPolicy = SimpleCopyPolicy>
class simple_auto_resource : public ReleasePolicy, public CopyPolicy
{
public:
    typedef simple_auto_resource<Resource,ReleasePolicy,CopyPolicy> base_type;

    simple_auto_resource() : res(0) {}
    simple_auto_resource(const Resource & r) : res(copy(r)) {}
    ~simple_auto_resource() { if(res) release(res); }

    void clear() { if(res) release(res); res = 0; }

    Resource& get() { return res; }
    const Resource& get() const { return res; }

    Resource detach() { Resource ret = res; res = 0; return ret; }

    operator const Resource&() const { return get(); }
    operator Resource&() { return get(); }

    base_type& operator=(const Resource& rhs) { clear(); res = copy(rhs); return * this; }

    template<class Comp> bool operator==(const Comp& rhs) const { return res == (Resource)rhs; }
    template<class Comp> bool operator!=(const Comp& rhs) const { return res != (Resource)rhs; }
    template<class Comp> bool operator<(const Comp& rhs) const { return res < (Resource)rhs; }
private:
    Resource res;
};

typedef simple_auto_resource<CRITICAL_SECTION, CritsecReleasePolicy> auto_critsec;
typedef simple_auto_resource<SOCKET,SocketReleasePolicy> auto_socket;

Подробнее о разработке на основе политик см. Современный дизайн C ++ .

...

0 голосов
/ 11 июня 2010

Переместите функцию из class Strategy<T>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...