应用基于策略的设计问题

时间:2010-04-04 20:14:14

标签: c++ policy-injection

我没有阅读过现代C ++设计书籍,但已经发现通过模板注释行为的想法很有趣。我现在正试图自己应用它。

我有一个具有记录器的类,我认为可以将其作为策略注入。记录器有一个log()方法,根据其策略采用std :: string或std :: wstring:

// basic_logger.hpp
template<class String>
class basic_logger
{
public:
    typedef String string_type;

    void log(const string_type & s) { ... }
};
typedef basic_logger<std::string> logger;
typedef basic_logger<std::wstring> wlogger;

// reader.hpp
template<class Logger = logger>
class reader
{
public:
    typedef Logger logger_type;

    void read()
    {
        _logger.log("Reading...");
    }

private:
    logger_type _logger;
};

现在的问题是,如果读者将Logger作为参数,如上所述,还是应该使用String然后将basic_logger实例化为实例变量?像这样:

template<class String>
class reader
{
public:
    typedef String string_type;
    typedef basic_logger<string_type> logger_type;

    // ...

private:
    logger_type _logger;
};

什么是正确的方法?

3 个答案:

答案 0 :(得分:2)

要实际使用策略类,策略必须是模板参数。一个例子是basic_string的char_traits参数,尽管它的实现方式与MC ++ D的策略不同,后者使用继承来利用空基类优化,并允许轻松添加到类的公共接口(以比包装每个可能的方法;再次,阅读MC ++ D)。您仍然可以提供默认值:

template<class String, class Logger=basic_logger<String> >
struct reader : Logger {
  void read() {
    this->log("Reading...");
  }
};

答案 1 :(得分:1)

问题是读者应该根据其记录器的类型或它所读取的东西的类型进行参数化吗?如果这是问题,我会认为答案很明显 - 后者。

这个问题的问题恕我直言,String和Logger都不是实际的策略。一个策略在编译时说,记录器应该如何记录日志 - 你的代码只是向阅读器提供一种记录器,同样可以在运行时使用继承来完成。

答案 2 :(得分:1)

策略通常是影响类行为的参数。

从类中提取策略实际上非常困难,而且更难以理解的是策略需要涵盖正交概念,以便您可以在不影响其他策略的情况下进行更改...这是您可以想象的非常具有挑战性的。

如果您想查看政策使用的一个很好的示例,请查看本书中完整演示的Loki::Singleton

template
<
  typename T,
  template <class> class CreationPolicy = CreateUsingNew,
  template <class> class LifetimePolicy = DefaultLifetime,
  template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
  class MutexPolicy = LOKI_DEFAULT_MUTEX
>
class SingletonHolder;

令人印象深刻,不是吗?

基于策略的设计原则是您尝试分解课程的各种动作,以便您可以独立地推理它们。

好吧,现在我必须承认我对要求具有一定数量的模板参数的类的想法并不十分舒服,我个人会喜欢这样的事情:

template
<
  class T,
  class CreationPolicy = CreateUsingNew<T>,
  class LifetimePolicy = DefaultLifeTime<T>,
  class MutexPolicy = LOKI_DEFAULT_MUTEX,
  template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL
>
class SingletonHolder;

最后一个不能真正得到帮助,你应该将它传递给SingletonHolder类本身。

但是我发现在这里交换策略更容易,它允许我定义如下的策略:

template <class T, size_t Param> MyCreationPolicy;

直接使用而不必为给定的param值包装它,以便它与签名匹配。