2

我没有读过 Modern C++ Design 这本书,但发现通过模板进行行为注入的想法很有趣。我现在正在尝试自己应用它。

我有一个类有一个我认为可以作为策略注入的记录器。记录器有一个 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;
};

正确的方法是什么?

4

3 回答 3

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...");
  }
};
于 2010-04-04T20:32:52.700 回答
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 值包装它,以便它与签名匹配。

于 2010-04-05T11:59:25.230 回答
1

问题是应该将阅读器参数化为其记录器的类型,还是它所读取的东西的类型?如果这是问题,我会认为答案是显而易见的——后者。

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

于 2010-04-04T20:21:07.227 回答