Та же самая основная проблема, с которой вы часто сталкиваетесь в объектно-ориентированном программировании, правилах стиля и почти во всем остальном. Возможно - на самом деле очень распространено - делать слишком много абстракций и добавлять слишком много косвенных указаний, и, как правило, применять чрезмерно хорошие методы в неправильных местах.
Каждый шаблон или другая конструкция, которую вы применяете, приносит сложность. Абстракция и косвенность рассеивают информацию, иногда удаляя ненужные детали с пути, но в равной степени затрудняя точное понимание того, что происходит. Каждое правило, которое вы применяете, приносит негибкость, исключая варианты, которые могут быть лучшим подходом.
Суть в том, чтобы написать код, который выполняет свою работу и является надежным, читаемым и обслуживаемым. Вы разработчик программного обеспечения, а не строитель башни из слоновой кости.
Соответствующие ссылки
http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx
http://www.joelonsoftware.com/articles/fog0000000018.html
Вероятно, самая простая форма внедрения зависимости (не смейтесь) - это параметр. Зависимый код зависит от данных, и эти данные вводятся посредством передачи параметра.
Да, это глупо и не затрагивает объектно-ориентированную точку внедрения зависимости, но функциональный программист скажет вам, что (если у вас есть функции первого класса), это единственный вид внедрения зависимости, который вам нужен. Суть в том, чтобы взять тривиальный пример и показать потенциальные проблемы.
Давайте возьмем эту простую традиционную функцию - синтаксис C ++ здесь не имеет значения, но я должен как-то это прописать ...
void Say_Hello_World ()
{
std::cout << "Hello World" << std::endl;
}
У меня есть зависимость, которую я хочу извлечь и вставить - текст «Hello World». Достаточно просто ...
void Say_Something (const char *p_text)
{
std::cout << p_text << std::endl;
}
Как это более негибко, чем оригинал? Что ж, если я решу, что на выходе должен быть Unicode. Я, вероятно, хочу переключиться с std :: cout на std :: wcout. Но это означает, что мои строки должны быть wchar_t, а не char. Либо каждый вызывающий объект должен быть изменен, либо (более разумно) старая реализация заменяется адаптером, который переводит строку и вызывает новую реализацию.
Это работа по техническому обслуживанию, которая не понадобилась бы, если бы мы сохранили оригинал.
И если это кажется тривиальным, взгляните на эту реальную функцию из Win32 API ...
http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx
Это 12 "зависимостей" для решения. Например, если разрешение экрана становится действительно огромным, возможно, нам понадобятся 64-битные значения координат - и другая версия CreateWindowEx. И да, уже есть старая версия, которая все еще висит вокруг, которая предположительно отображается за кулисами новой версии ...
http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx
Эти «зависимости» не являются проблемой для первоначального разработчика - каждый, кто использует этот интерфейс, должен посмотреть, что это за зависимости, как они определены и что они означают, и решить, что делать для их приложения. Именно здесь слова «разумные значения по умолчанию» могут сделать жизнь намного проще.
Объектно-ориентированное внедрение зависимостей в принципе не отличается. Написание класса - это непроизводительные затраты как в тексте исходного кода, так и во время разработки, и если этот класс написан для предоставления зависимостей в соответствии с некоторыми спецификациями зависимых объектов, то зависимый объект блокируется для поддержки этого интерфейса, даже если есть необходимость заменить реализацию этого объекта.
Ничто из этого не должно восприниматься как утверждение, что внедрение зависимостей является плохим - это далеко не так. Но любая хорошая техника может применяться чрезмерно и не в том месте. Так же, как не каждая строка должна быть извлечена и превращена в параметр, не все низкоуровневые действия должны быть извлечены из высокоуровневых объектов и превращены в инъекционную зависимость.