Почему предпочитают шаблонный метод над внедрением зависимости? - PullRequest
9 голосов
/ 15 ноября 2011

Я читал Design Patterns, Gamma et al. У меня есть вопрос, касающийся метода шаблонов по сравнению с внедрением зависимостей.

С помощью Template Template вы «шаблонируете» классы с помощью политик, которые предоставляют альтернативы для необходимых действий или расчетов. Поэтому вместо того, чтобы выбирать одну политику из нескольких альтернатив и кодировать эту политику в классе, вы позволяете пользователю класса указать альтернативу, которую он хочет использовать.

Все это звучит очень разумно для меня. Но я наткнулся на концептуальную кирпичную стену.

Если вы создаете экземпляр класса с объектом политики, объект политики должен реализовать абстрактный интерфейс. Затем программист может написать разные политики, которые все безошибочно компилируются в класс, потому что политики реализуют интерфейс. Класс, использующий политики, кодируется для интерфейса политики, а не для реализации.

Если вы собираетесь определить реферат IPolicy для этих объектов политики, почему бы просто не использовать Dependency Injection и передать IPolicy on construction?

Может ли кто-нибудь пролить свет на то, почему вы предпочитаете шаблонный метод внедрению зависимости?

Ответы [ 3 ]

14 голосов
/ 15 ноября 2011

Относительно «метода шаблона» (а не шаблона проектирования), следующий пример может помочь с за и против относительно того, что решать, что делать. Примером является создание подробного режима библиотеки, предназначенной для помощи при отладке / разработке.

С шаблонами

struct console_print
{
  static void print(const string& msg) {std::cout<<msg;}
};

struct dont_print
{
  static void print(const string& msg) {}
};

template<printer>
void some_function()
{
  printer::print("some_function called\n");
}

Пользователь библиотеки может написать:

some_function<console_print>(); //print the verbose message;
some_function<dont_print>();    //don't print any messages.

Преимущество этого кода в том, что если пользователь не хочет, чтобы код печатался, тогда вызовы dont_print::print(msg) полностью исчезают из кода (пустые статические классы легко оптимизируются). Такие отладочные сообщения можно затем вводить даже в критические области производительности.

Недостаток шаблонов заключается в том, что вам необходимо определить свою политику перед компиляцией. Вам также необходимо изменить сигнатуру функции / класса для любого шаблона.

без шаблонов

Выше можно, конечно, сделать что-то вроде:

struct printer 
{
  virtual void print(const std::string& msg) = 0;
}

struct console_print : public printer
{
  void print(const std::string& msg) {std::cout<<msg;}
}
struct debug_print : public printer
{
  void print(const std::string& msg) {}
}

Преимущество этого в том, что вы можете передавать типы принтеров своим классам и функциям и изменять их во время выполнения (может быть очень полезно для некоторых приложений). Однако стоимость заключается в том, что вызов виртуальной функции всегда выполняется, и поэтому пустой dont_print имеет небольшую стоимость. Это может или не может быть приемлемо для критических областей производительности.

7 голосов
/ 15 ноября 2011

Во-первых, как упомянул Френель, шаблон «Шаблонный метод» является , а не шаблоном в современном понимании. Прочтите еще раз, он использует полиморфизм во время выполнения для достижения той же цели, для которой алгоритмы STL используют полиморфизм во время компиляции (шаблоны функций).

Во-вторых, все виды полиморфизма, в некотором смысле, являются зависимой инъекцией. То есть вызывающая сторона вводит алгоритм в конкретный тип, на который он действует. Таким образом, вопрос, как правило, заключается не в том, можете ли вы или должны использовать внедрение зависимостей вместо какого-либо другого шаблона: скорее шаблон показывает полезный способ структурирования вашего кода для использования внедрения зависимостей.

Если ваша «введенная зависимость» является параметром типа шаблона, алгоритм использует типизацию утки, и вам не нужно реализовывать абстрактный интерфейс: просто напишите методы с ожидаемой сигнатурой.

2 голосов
/ 15 ноября 2011

«Метод шаблона» в вашем случае (не путайте с Шаблон метода шаблона ) или, если мы назовем его «внедрение статической зависимости», избавит от необходимости использования виртуальных функций. Вы получаете производительность прежде всего, давая компилятору больше и определенные знания, и, следовательно, даете ему лучшую возможность для оптимизации. Классы становятся более статичными и безопасность типов увеличивается.

Размер класса потенциально может уменьшиться (нет необходимости хранить указатели или уменьшить его).

Старая поговорка:

Не плати за то, что не используешь.

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

...