Впорскування в залежності: Чи слід створити клас "Автомобіль", щоб вмістити всі його частини?


10

У моєму додатку C ++ є багато автомобілів, які містяться у RaceTrack.

Кожна машина складається з сотень деталей. Кожна частина залежить від якоїсь іншої частини чи двох.

Я прочитав багато запитань ТА щодо книги Д.І. та Марка Семана, і, схоже, я не повинен визначати клас «Автомобіль» лише для того, щоб утримувати деталі автомобіля, тому що всі деталі автомобіля залежатимуть один від одного, і цей суп частин - це машина. Чи правий я?

Тож коли я розміщую всі мої гоночні автомобілі на RaceTrack, не буде автомобільних сутностей, а багато автомобільних частин залежно від перегонів один на одного на трасі ?? Чи правий я?

Редагувати:

Протягом століть я програмував Автомобільні класи, тому що для мене було очевидно, що мені потрібен клас "Автомобіль", якщо я програмую логіку автомобіля. Але з DI це для мене не так очевидно. Все ще цікаво, чи це ідіоматичне для DI не створювати клас автомобілів, якщо я не маю для нього визначеної ролі?

Я маю на увазі, чи добре мати SteeringWheel для водіння, BoltsAndNuts на колесах для піт-екіпажу та всілякі інші смішні інтерфейси, не маючи примірника, який представляє автомобіль у цілому?

Відповіді:


24

Яку користь купу автомобільних частин, що сидять на гоночній трасі, хто робить?

Якщо у вашому класі автомобілів є автозапчастини, це так само корисно, як і вологий мішок з деталями.

Використання

Як водій, я хочу контролювати те, що я хочу. Це відповідає, коли я прошу швидкості. Це ручки, як його на рейках. Це може зупинитися на копійці.

Що я хочу - це клас автомобілів, який можна використовувати. Що я можу сказати робити речі, не замислюючись про те, як працює карбюратор. Я просто думаю про педаль газу. Те, як вони пов’язані, не хвилюється. Це абстракція.

Ін'єкційна залежність

Ін'єкція залежності не має нічого спільного з цим. Коли я за кермом автомобіля, я не замислююся про те, як він був побудований. Поки це працює, мені не байдуже, як вони це складають.

Ні, DI - це те, що дозволяє моєму піт-екіпажу швидко міняти свої шини на кращі, коли на доріжці починає дощ. Приємно бути в змозі зробити це без того, щоб стрибати у зовсім інший автомобіль.

DI дійсно стосується принципу: Окреме використання від будівництва.

Автомобіль, який може встановити нові шини за швидкість 90 миль на годину, може здатися здоровим, але я не думаю, що він не виграє жодних перегонів, якщо шина встановить на ньому контрацепцію.

DI - це встановлення деталей таким чином, щоб ваш екіпаж ями дістався до них. Якщо ви користуєтесь newтам же, ви програмуєте поведінку, це так, ніби ви зварюєте карбюратор на місце. Впевнені, що ацетиленовий факел може його зняти, але, будь ласка, спочатку подумайте про використання гайок і болтів.

Ось що таке DI. Впевнений, що це не так просто, як newпідготувати щось, як тільки ти зрозумієш, що цього хочеш. Натомість вам потрібно написати окремий код, який знає, як побудувати свій автомобіль. Але це впевнено полегшує змінити речі згодом. А це означає, що вам не доведеться перетягувати завод збору автомобілів навколо колії.

Будівництво

Щось десь має знати, чи є шини Goodyear. Куди тоді поставити код будівництва автомобіля? Якщо не машина, то піт-екіпаж? Ні. Доріжка? Ні. Усі мають код поведінки. Код, який повинен виконувати під час гонки. Побудова автомобіля повинна відбуватися перед гонкою в місці, усуненому від коду поведінки. Марк Сейманс назвав це місце складом корінь . Більшість людей називає це головним.

Це проста модель. В основному, побудуйте графік об'єкта, а потім викликайте один метод поведінки на одному об'єкті в об'єктному графіку. Це воно. Це ТІЛЬКИ будівництво місця та поведінка повинні бути разом.

Це не означає, що конструкція має бути купою процедурного кодексу, викладеного послідовно в основному. Ви можете вільно користуватися будь-яким інструментом на мові для будівництва. Просто не змішуйте це з поведінкою.

Робити це мовою, а не використовувати якусь рамку DI чи контейнер IoC, називається чистим DI . Це працює дуже добре. Має давно. Ми звикли просто називати це посиланням проходженням .

Інструменти DI

Що вам купує інструмент DI - це деталі побудови, переміщені на іншу мову (xml, json, будь-яку іншу), яка примушує розмежувати конструкцію та поведінку. Якщо ви не довіряєте своїм колегам-програмістам не користуватися, newколи вони не повинні, це може бути привабливим.

Зворотний результат полягає в тому, що детально про інструмент DI розповсюджуватись по всій кодовій базі непросто. Іноді заражає кодову базу власними анотаціями. Наведені ними приклади, безумовно, заохочують це. Інструмент, як правило, рухається в мовному просторі, поки ви не зможете просто рекламувати завдання як завдання програмування Java, але як завдання програмування Java / Spring.

Принципи дизайну

Протягом століть я програмував Автомобільні класи, тому що для мене було очевидно, що мені потрібен клас "Автомобіль", якщо я програмую логіку автомобіля. Але з DI це для мене не так очевидно. Все ще цікаво, чи це ідіоматичне для DI не створювати клас автомобілів, якщо я не маю для нього визначеної ролі?

Я думаю, ви дізнаєтесь про абстракцію та зміните те, як вирішите, що клас потрібен. Це добре. Але справа не в DI. DI не допоможе вам вирішити, чи потрібен вам автомобільний клас. DI допомагає вам уникнути того, щоб автомобіль не знав, а для цього дбали, якщо шини - це шини Goodyear. DI допомагає вам не відслідковувати, чи автомобілі зроблені в Японії.

Одне з найбільш фундаментальних питань в розробці програмного забезпечення - "що знає про що?" Це головне, що вам показує діаграма UML. Коли ви створюєте щось нове, до якого ви досягаєте минулого, це інтерфейс до конкретної речі, до якої ви зараз прив'язані. Автомобіль тепер повинен знати, що шини - це Goodyear. Що ні за що не підходить, якщо Мішелін хоче спонсорувати вас.

Уникати цього потрібно називати за принципом інверсії залежності . Формально модуль високого рівня (як автомобільний клас) не повинен безпосередньо залежати від модулів низького рівня (наприклад, клас GoodyearTire). Це має залежати від абстракції (як інтерфейс шини).

Спосіб уникнути цього називається Інверсія управління . Тут акцент робиться на зміні потоку управління. Чи шини переміщують машину чи автомобіль переміщує шини? Думаючи про це правильний спосіб дозволяє нам не статично з'єднувати автомобіль та шини разом. DI - це один із певних способів слідувати Інверсії управління.

Ніщо з цього не говорить про те, чи потрібен вам автомобільний клас. Якщо ви програмуєте "логіку автомобіля", це добре, якщо є одне місце, щоб зберегти його, а не розкидати його кудись. Тільки не обманюйтеся, що логіка побудови автомобіля така ж, як логіка поведінки автомобіля, тому все має жити там же. Але якщо у вас немає визначеного рулону для машини, то вам також не потрібен. Перегони мотоциклів навколо доріжки, якщо вам подобається.

Я маю на увазі, чи добре мати SteeringWheel для водіння, BoltsAndNuts на колесах для піт-екіпажу та всілякі інші смішні інтерфейси, не маючи примірника, який представляє автомобіль у цілому?

DI чи ні DI, це добре мати екземпляр, який представляє автомобіль в цілому, але цей екземпляр - це не те, про що я хочу знати безпосередньо, якщо мені цього не потрібно. Дайте мені автомобільну абстракцію, щоб мені не було байдуже, чи працює вона на газі, дизелі чи електриці, коли я ним користуюся. Це лише те, про що я повинен дбати, коли будую його чи підтримую. Приємно, якщо код, який використовує автомобіль, не повинен знати або дбати, як він працює. "Я не знаю. Я не хочу знати".


Було б здорово, якби ви не використовували метафору автомобіля та піт-екіпажу для питання, яке використовує їх для представлення коду. Але все-таки хороша відповідь.
S. Tarık Çetin

6
І я завжди думав, що Інверсія управління була, коли ви
рухаєтеся

CandiedOrange, так що немає автомобільного класу, якщо він не має змістовного інтерфейсу і чітко визначеної відповідальності? І в моєму проекті немає Car.h. А колега, що заглядає в мій код і цікавиться, чи це електронний магазин або додаток для управління гаражем? :)
Антон Петров

@AntonPetrov "якщо він схожий на качку і трясеться як качка, але потрібні батарейки, ви, мабуть, маєте неправильну абстракцію". Гарні імена дуже важливі і їх важко придумати, але їх слід змінити, щоб відобразити чітко визначену відповідальність та змістовний інтерфейс, щоб вони не стали несподіванкою. Якщо я прочитаю ім'я, то подивіться на інтерфейс і думаю "це майже те, що я очікував", то ви маєте гарне ім'я.
candied_orange

15

схоже, я не повинен визначати клас «Автомобіль» лише для того, щоб утримувати автозапчастини, оскільки всі деталі автомобіля залежатимуть один від одного, і цей суп деталей - це машина. Чи правий я?

Ні.

Суть введення залежності зовсім не в тому, щоб стримувати залежності. Зовсім навпаки.

Залежність від ін'єкції близько питання: де ж автомобіль отримати його частини від ? Де і як вони створюються, і як машина отримує посилання на них?

Наївно, автомобіль сам би створив свої частини, зателефонувавши new. Це легко і просто, але дуже негнучко. Автомобіль повинен знати все, що необхідно для створення деталей, і якщо ви коли-небудь хочете мати дві машини з різними частинами, така логіка повинна також зайти в машину.

За допомогою вприскування залежності вся ця логіка виймається з машини та вкладається в конфігураційний компонент, який створює всі деталі та з'єднує посилання. Повністю налаштовані залежності вводяться в машину - і одна в одну.


1
Нарешті, розумне пояснення dependency injectionконцепції.
anatoly techtonik

1
Я б сказав, що більш поширеною системою «наївного» підходу є не те, що автомобіль називатиме новим, а те, що користувач автомобільного класу присвоює його частини своїм властивостям, а тим часом клас автомобіля буде в невизначений стан. DI забезпечує засіб механічного забезпечення валідності класу.
whatsisname

2
@whatsisname Я легко можу використовувати DI для створення недійсних та наполовину ініціалізованих об'єктів. Валідація не є відповідальністю DI. Не може бути незмінним. DI може взяти на себе роботу зі створення дійсних та незмінних об'єктів. У DI немає способу переконатись, що це єдині способи побудови та використання цих об'єктів. Об'єкти повинні це застосувати.
candied_orange

@CandiedOrange: так що ви можете легко використовувати будь-яку техніку, щоб зробити щось напівзвукове, і що? Вимагати залежностей від конструктора та зробити їх непорушними - це не срібна куля, але, тим не менш, це дуже корисний спосіб запобігання багатьом звичайним поганим ситуаціям.
whatsisname

0

Тож коли я розміщую всі мої гоночні автомобілі на RaceTrack, не буде автомобільних сутностей, а багато автомобільних частин залежно від перегонів один на одного на трасі ?? Чи правий я?

Добре. Так і ні. Автомобіль все ще дійсний. А автомобіль - це більше, ніж сума його частин. Вам також потрібен водій (поки що). Багато разів гоночні машини мають імена, не кажучи вже про Марку та Модель автомобіля.

Так, машини в основному є контейнером деталей, але саме ця упаковка та співпраця деталей складають щось більше: автомобіль.

Так справді, ні. Автомобіль - це не просто випадковий мішок із металу та пластику. Це машина.

Введення залежності в цьому випадку не є надмірним. Щось інше має побудувати автомобіль, який би був заводським класом або об’єктом Builder. Автомобіль не повинен знати, як будувати себе.


2
Ви можете мати DI без фабрик чи будівельних об'єктів. Прості параметри конструктора - це дійсний метод, який працює за багатьох обставин.
whatsisname
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.