Применение основанного на политике дизайна вопроса - PullRequest
3 голосов
/ 05 апреля 2010

Я не читал книгу 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;
};

Какой правильный путь?

Ответы [ 3 ]

2 голосов
/ 05 апреля 2010

Чтобы фактически использовать класс политики, политика должна быть параметром шаблона.Одним из примеров является параметр char_traits для basic_string, хотя он реализован не так, как политики MC ++ D, в которых наследование используется для оптимизации пустого базового класса и позволяет легко добавлять открытый интерфейс класса (гораздо лучшеоборачивая каждый возможный метод, снова прочитайте MC ++ D).Вы по-прежнему можете указать значение по умолчанию:

template<class String, class Logger=basic_logger<String> >
struct reader : Logger {
  void read() {
    this->log("Reading...");
  }
};
1 голос
/ 05 апреля 2010

Политики обычно являются параметрами, которые влияют на поведение класса.

Фактически довольно сложно извлечь политики из класса, и более сложным является то, что политики должны охватывать ортогональные концепции, чтобы вы могли изменить одно, не влияя на другие ... что довольно сложно, как вы можете себе представить.

Если вы хотите увидеть хороший пример использования Политики, посмотрите 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, чтобы оно совпадало с подписью.

1 голос
/ 05 апреля 2010

Является ли вопрос, должен ли читатель быть параметризован по типу его регистратора или по типу того, что он читает? Если бы это был вопрос, я бы подумал, что ответ очевиден - последний.

Проблема с этим вопросом ИМХО заключается в том, что ни String, ни Logger на самом деле не являются политиками. Политика говорит во время компиляции, как что-то вроде логгера должно идти о регистрации - ваш код просто предоставляет читателю тип логгера, который можно было бы сделать во время выполнения с использованием наследования.

...