Та сама основна проблема, яку ви часто зустрічаєте з об'єктно-орієнтованим програмуванням, правилами стилів і майже з усім іншим. Можна - дуже часто насправді - робити занадто велику абстракцію і додавати занадто багато непрямості, і взагалі застосовувати хороші прийоми надмірно і в неправильних місцях.
Кожен візерунок або інша конструкція, яку ви застосовуєте, приносить складність. Абстракція та опосередкованість розкидають інформацію навколо, часом відсуваючи невідповідні деталі в сторону, але однаково іноді ускладнюють розуміння того, що відбувається. Кожне правило, яке ви застосовуєте, приносить гнучкість, виключаючи варіанти, які можуть бути просто найкращим підходом.
Сенс у тому, щоб написати код, який виконує цю роботу, і є надійним, читабельним та доступним для обслуговування. Ви розробник програмного забезпечення - не виробник вежі зі слонової кістки.
Відповідні посилання
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. Будь-який абонент повинен бути змінений, або (більш розумно) стару реалізацію заміняють адаптером, який переводить рядок і викликає нову реалізацію.
Це роботи з технічного обслуговування, які не знадобляться, якби ми зберегли оригінал.
І якщо це здається тривіальним, погляньте на цю функцію в реальному світі від API Win32 ...
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
Ці "залежності" не є проблемою для оригінального розробника - кожен, хто використовує цей інтерфейс, повинен шукати, що таке залежності, як вони вказані та що вони означають, і розробити, що робити для їх застосування. Саме тут слова "розумні дефолти" можуть зробити життя набагато простішим.
Об'єктно-орієнтована ін'єкційна залежність принципово не відрізняється. Написання класу є накладними, як у тексті вихідного коду, так і в часі розробника, і якщо цей клас записується для забезпечення залежностей відповідно до деяких специфікацій залежних об'єктів, то залежний об'єкт замикається на підтримку цього інтерфейсу, навіть якщо є потреба замінити реалізацію цього об’єкта.
Нічого з цього не слід сприймати як твердження, що ін'єкція залежності є поганою - далеко не так. Але будь-яку хорошу техніку можна застосовувати надмірно і в неправильному місці. Так само, як не кожну рядок потрібно витягувати та перетворювати в параметр, не кожну поведінку низького рівня потрібно витягувати з об'єктів високого рівня та перетворювати на залежність, яку можна вводити.