【问题标题】:template strategy pattern模板策略模式
【发布时间】:2010-06-11 11:33:19
【问题描述】:

我想分解一个类,使其与执行某些任务的逻辑分离,以便用户可以根据需要编写新策略,而不会干扰中心模型。所以,我想使用模板化策略类,但不必让策略的用户被模板化:

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

我希望 DoSomething 函数不被模板化。有没有其他方法可以实现我想要在这里做的事情?

谢谢。

【问题讨论】:

  • 您正在参数化DoSomething 中的数据成员。它甚至是如何编译的?而T又是从哪里来的Strategy &lt; T &gt;呢?

标签: c++ templates


【解决方案1】:

在我看来,您想要实现的是Policy-Based Design。我不确定ModelStrategy 究竟做了什么,但似乎Model 是根类,而Strategy 是Policy 类,在某些情况下用户希望提供它来执行特殊处理.似乎您保留指向 Strategy&lt;T&gt; 对象的指针的唯一原因是,您可以在其上调用函数。

在这种情况下,你可以这样设计你的类:

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_resourceStrategy 将变为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 互斥锁HANDLEs 的新策略:

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_SECTIONs,另一套适用于 SOCKETs:

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;

有关基于策略的设计的更多信息,请参阅Modern C++ Design

...

【讨论】:

  • 感谢您的精彩回答... :)
  • 已经 2 年多了.. 但这是好东西。让我问你一下。 strategy patternpolicy based pattern 有何不同?我从您的代码中看到的一件事是不同上下文的主题,具有非常相似的策略算法。套接字、指针和句柄释放策略都适用于不同的上下文:套接字指针和句柄。我正在寻找的 设计模式 是当上下文是恒定的,但算法/协议是唯一的。所以也许有两个区别需要 policy pattern 的许多上下文和 strategy pattern 的许多协议
  • 也许我会在一个新的线程/问题中讨论我的设计问题...但是我很难使用现代 C++ 设计来实现策略模式 技术.. 就像你上面的代码。我不想使用任何虚函数,但没有进入 Boost::MPI 类型的东西,我很难设计我的策略模式。有什么建议吗? ty @Grunch
【解决方案2】:

将函数移出class Strategy&lt;T&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-03
    相关资源
    最近更新 更多