No video

SOLID, 1.5 DIP - Dependency Inversion Principle, Принцип инверсии зависимости, С#, Unity

  Рет қаралды 7,425

Sergey Kazantsev

Sergey Kazantsev

Күн бұрын

Наконец-то добил SOLID :)
Другие принципы SOLID-а
SRP - Принцип единственной ответственности • SOLID, 1.1 SRP - Singl...
OCP - Принцип открытости закрытости • SOLID, 1.2 OCP - Open ...
LSP - Принцип подстановки Лисков • SOLID, 1.3 LSP - Lisko...
ISP - Принцип сегрегации интерфейсов • SOLID, 1.4 ISP - Inter...
Автору на кофе и шаурму
4276 5500 5792 8742 - карта Сбербанка
Если будут вопросы
мой тг @wargy
моя почта kazancev.s215@gmail.com
Тайминги
00:00 Введение
00:20 Важность DIP по сравнению с остальными правилами SOLID
00:45 Определение DIP
01:19 Пример: DIP в жизни
03:07 Пример: DIP в геймдеве
04:00 DIP простыми словами
05:11 Конкретный пример: введение
06:04 Конкретный пример: пишем код без DIP
07:18 Конкретный пример: пишем код с DIP
08:43 Конкретный пример: сравнение кода с DIP и без DIP
09:23 Inversion of Control, инверсия потока управления на вышеуказанном примере
11:37 Dependency Inversion, схема инверсии зависимости
12:25 Когда следовать DIP?
13:08 Финал

Пікірлер: 76
@evan_kirk
@evan_kirk 19 күн бұрын
Браво! Отличнейшее объяснение. До просмотра данного ролика смутно понимал DIP. Но после будто прозрел. Спасибо огромное 🔥
@user-mm7ch3xw4e
@user-mm7ch3xw4e Жыл бұрын
Полезная информация! Объяснение - ОГОНЬ!!!
@micvist
@micvist Жыл бұрын
Первый раз посмотрел - понял процентов 20, отдохнул полчаса - пересмотрел с паузами - разобрался. Автор - спасибо)
@user-lk2cq2fp2f
@user-lk2cq2fp2f Жыл бұрын
потрясающее объяснение принципа Dependency Inversion и других принципов SOLID👌
@user-gp7js3zu6b
@user-gp7js3zu6b Жыл бұрын
Как же круто!!! Это кайф, когда информация сразу зоходит, без пересмотров и долгих осмыслений. Спасибо! Это лучшее объяснение!!!! Жду с нетерпением новых видосов. Автору огромное спасибо за труд!!!
@wepko
@wepko 10 ай бұрын
И не говори, это правда. Просто не вероятно, сразу все понятно. Идеально просто лучший. Я очень сильно удивлен
@harryworner8684
@harryworner8684 4 ай бұрын
Просто восхитительное видео как и предыдущие! Очень благодарен за четкое и понятное объяснение принципов SOLID для Unity. Ваши примеры помогли лучше понять эти концепции. Продолжайте в том же духе! 👍👍👍
@user-gm6ks7si4s
@user-gm6ks7si4s Жыл бұрын
Очень понятное видео, невероятно понравилось объяснение)) И прекрасные, наглядные схемы.
@Ivan-GameDev
@Ivan-GameDev 10 ай бұрын
это точно. На личном опыте убедился. Решил добавить ма-а-а-а-ленькую фичу, пришлось переписать 250 строк кода в нескольких классах высокого уровня
@citizen4_223
@citizen4_223 Жыл бұрын
Сергей, вы большой молодец!👍 Посмотрел несколько видео - отличные объяснения и визуализации, а смотрел и читал я немало видео/статей на эти темы у разных авторов. Буду поддерживать лайками и надеюсь смотивирую на продолжение деятельности😊
@sergeykazantsev1655
@sergeykazantsev1655 Жыл бұрын
Спасибо! Да, лайки и комментарии меня действительно мотивируют)
@user-kr2wu9gi1r
@user-kr2wu9gi1r Жыл бұрын
Лучшее обьяснение данного принципа из тех что мне встречались Отличная работа!
@GorMax123456
@GorMax123456 Жыл бұрын
Просмотрел все ролики про солид, до этого видел их уже не мало, и именно тут всё растолковано на отлично. Примеры и схемы, дают больше понимания, чем простое зачитывание текста авторами видео.
@user-hk8sh7zb4c
@user-hk8sh7zb4c Жыл бұрын
Спасибо большое за твои старания! Продолжай пожалуйста рассказывать обо всём этом. Ты очень здорово, а самое главное, по-житейски объясняешь. Всё отлайкаем, поднимем в топы) Как вариант рассказать о структурных, поведенческих и порождающих паттернах, я думаю это будет шикарно!
@user-ne4zy2jm9j
@user-ne4zy2jm9j 2 ай бұрын
Это шок! Автор сразу же объясняет мои вопросы в момент их возникновения. Давненько такого качественного контента не видел. Молодцом!
@h.valors7251
@h.valors7251 Жыл бұрын
Хороший ролик! Лучший материал, объясняющий этот принцип, из тех, что я нашёл.
@PRO-pt6ew
@PRO-pt6ew 7 ай бұрын
Лучшие объяснения!
@user-yj8tf7xb6g
@user-yj8tf7xb6g Жыл бұрын
Очень хорошее объяснение и замедление, где нужно 👍 спасибо!
@user-xb3on3fl6n
@user-xb3on3fl6n Жыл бұрын
Хорошее видео. Наглядно, содержательно. Автору успехов.
@ilyatrukhin5992
@ilyatrukhin5992 Жыл бұрын
Великолепное объяснение! Благодарю
@AleksandrFoman
@AleksandrFoman 5 ай бұрын
Корисний контент, дякую
@user-kp5rb3yo5m
@user-kp5rb3yo5m 6 ай бұрын
Сергей, спасибо! Очень доходчиво. Классные примеры и главное - сказано зачем всё это нужно и для чего.
@deluxetv8961
@deluxetv8961 Жыл бұрын
Отличное обяснение! Спасибо большое!
@mikki5923
@mikki5923 Жыл бұрын
Круто, круто
@sergeykazantsev1655
@sergeykazantsev1655 Жыл бұрын
Спасибо за тёплые слова)
@elementarist1991
@elementarist1991 6 ай бұрын
И почему так мало просмотров и лайков , это реально лучшее объяснение 🔥 Определенно подписка ❤
@botcser
@botcser 9 ай бұрын
Топ 2! Такое ощущение, что на ютубе всего два чела поняли DI и DIP и имеют навык объяснения, этот чел и еще codaza.
@ivannarykin
@ivannarykin Жыл бұрын
Thank you
@boost_456
@boost_456 3 ай бұрын
У вас невероятные видео. Всё максимально понятно, без всякой воды и странных примеров
@mistrebrown7642
@mistrebrown7642 2 ай бұрын
Отличный контент! Спасибо вам большое
@radari7180
@radari7180 8 ай бұрын
Большое спасибо
@user-vb1xw8sg4o
@user-vb1xw8sg4o Ай бұрын
Спасибо большое, классное видео
@PinkPanteRus
@PinkPanteRus Жыл бұрын
Спасибо!
@user-oe1hf4lu3x
@user-oe1hf4lu3x 11 ай бұрын
спасибки вам!)
@obusis
@obusis Жыл бұрын
Пойду ещё пересмотрю разок
@ivan-jc1bp
@ivan-jc1bp Жыл бұрын
Огромное спасибо вы лучший !
@sergeykazantsev1655
@sergeykazantsev1655 Жыл бұрын
как говорил Киану, "Нет, это вы лучший!"
@Serge86210
@Serge86210 4 ай бұрын
Мне кажется, что пример с IMovable - это про обобщение и контракт (LSP), а не про DIP. Из "википедий" у меня возникло понимание, что инверсия - это передача управления третьей стороне (BOTH should depend upon abstractions). Например, клиент и сервер связаны через протокол. В этом случае модуль Enemy и контроллер Movement должны быть связаны не через обобщение поведения (LSP), а через абстрактного посредника, реализующего инверсию зависимости.
@sergeykazantsev1655
@sergeykazantsev1655 4 ай бұрын
С момента публикации этого видео прошёл уже год и я действительно подумал что пример в DIP не самый удачный. Но уже появился в голове пример по лучше Принцип заключается в том что в основе должна быть работа с абстракциями. А чтобы прочувствовать почему она называется инверсией зависимостей - нужно написать решение одной и той же задачи, на условном Паскале или Бейсике, которые не ООП-шные и на каком-нибудь ООП языке. На не ООП-шных языках сразу чувствуется, что классы высокого уровня зависят от классов низкого, и те и другие зависят от деталей. И потому разработка идёт снизу вверх. А в ООП наоборот, разработка идёт от абстракции к деталям.
@rdragon587
@rdragon587 5 ай бұрын
Без инверсии зависимости реализация чем-то похожа на ECS подход)
@sergeykazantsev1655
@sergeykazantsev1655 5 ай бұрын
Да ECS вообще почти весь Солид игнорирует)
@mikki5923
@mikki5923 Жыл бұрын
Хм, я знаю, что вы сейчас делаете видео по Zenject, так что моё уважение. Жду с нетерпением. Однако, есть ли возможность в будущем пройтись по Структуральным паттернам(Фасад, Декоратор, Адаптер или Мост)?
@sergeykazantsev1655
@sergeykazantsev1655 Жыл бұрын
Если я закончу писать эту шайтан-машину с зенджектом, mvvm-ом и прочим, да, я займусь ими) Декоратор и GRASP в приоритете)
@scc-6
@scc-6 2 ай бұрын
Нихуя, ты расписал все буковки на 0:40, спс
@botcser
@botcser 9 ай бұрын
Товарищ шифу, вопрос: если в принципе без DIP сделать тоже самое, что и в DIP, а именно добавить поле в класс монстра и инитить его при создании, то как это будет называться и чем будет отличаться от полного предложенного DIP? Такое ощущение, что DIP тут притянут зауши, искусственный...
@sergeykazantsev1655
@sergeykazantsev1655 9 ай бұрын
Ключевая идея DIP - в основе кода должна быть работа с абстракциями а не с конкретными элементами. Детали зависят от абстракций, абстракции не зависят от деталей. Если нам нужно передвинуть всех врагов - вы можете засунуть их в один список IMovable и foreach-ем пробежаться. В целом если у каждого типа монстра будет уникальный Init, но опять же в самом коде мы работаем с ними как с базовым классом, игнорируя детали это всё ещё будет DIP. А вот если у каждого монстра будет уникальный Move и апкаст не поможет, тогда это будет DIP Пример действительно надо чуть чуть переделать, в моём последнем видео по ООП я пришёл к хорошему объяснению абстракции и DIP в частности на железнодорожных вагонах. Вагоны имеют разные типы, свойства, характеристики и функционал - это детали. Но что пассажирский вагон, что цистерна это вагон. И архитектура железных дорог выстроена так что ты по ним можешь перевозить как цистерны, так и пассажирские и в целом вся процедура перевозок вагонов от конкретных деталей не зависит.
@botcser
@botcser 9 ай бұрын
А в один список Object я разве не смогу засунуть, чтобы потом присунуть?)@@sergeykazantsev1655
@sergeykazantsev1655
@sergeykazantsev1655 9 ай бұрын
у Object-а нет метода Move() :D
@fervorezy
@fervorezy Жыл бұрын
суть в том, что мы запрещаем сами себе работать с деталями в классах высокого уровня?
@fervorezy
@fervorezy Жыл бұрын
а еще без абстракции не было бы класса, который содержал бы общие детали классов низкого уровня одного семейства
@sergeykazantsev1655
@sergeykazantsev1655 Жыл бұрын
Мы не запрещаем себе работать с деталями в классах высокого уровня. Мы делаем абстракцию как основу и именно с абстракцией мы работаем в классах высокого уровня. Если нам нужно поработать с деталями, мы создадим новый класс высокого уровня и в него поместим объекты с тем типом деталей, что нам нужны. У джавистов есть хороший пример. На работе есть три типа сотрудников: уборщик, айтишник и бухгалтер. Пусть у нас будет в фирме 3 уборщика, 4 айтишника и 5 бухгалтеров. Нужно написать код считающий сумму их зарплат. Если у нас нет абстракции Employee в коде, от которой 3 сотрудника наследуются, то чтобы такое реализовать нам нужно писать три цикла, один считает суммарную зп всех уборщиков, один айтишников и один бухгалтеров, потом всё это суммировать что довольно запарно. А если у нас есть абстракция Employee, и абстрактный метод GetSalary, мы просто бежим один раз циклом по объектам типа Employee, то есть по абстракциям и игнорируя детали. Если нам нужно посчитать зп для всех айтишников - мы создаём класс высокого уровня который считает зп только дня них. Как-то так
@user-co8vr7xp7o
@user-co8vr7xp7o Жыл бұрын
я бы дополнил: 1) тут не указан классический контейнер, а именно коллекция List _allMovable; который содержит абстракции, и двигает в update() { foreach (var movable in _allMovable) { movable.Move(moveParams); } }; 2) в видео умалчивается (а в комменте к видео поднимается вопрос) что при расширении логики и добавлении какого-то функционала, хотябы коэфф скорости только для ground, от самого принципа DIP мало толку, потому что будет меняться MoveParams, скажем там могут быть такие параметры class MoveParams {float speedCoeffWhenGround; float deltaTimeSec; } вернее изначально только deltaTimeSec, а когда нам пришла задача чтобы замедлять только ground то придется в moveParams (абстракцию) прокинуть speedCoeffWhenGround (или предложите свой вариант реализации, но полюбому если задача такова что нужно замедлять иногда - скажем временно вообще всех Ground или всех Ground в области баффа - это не в GroundEnemy() конструкторе параметр будет, это будут детали в Update или систему Buff делать и также прокидывать баффы в Enemy и коэффициенты в баффах держать, вобщем зависимости всеравно будут), но юзать этот speedCoeffWhenGround только внутри реализации GroundEnemy.Update(moveParams) { //use speedCoeffWhenGround * deltaTimeSec } а в других подклассах // не юзать speedCoeffWhenGround а юзать только deltaTimeSec; и такое повсеместно встречается, т.е. таки деталь - параметр придется прокидывать, а потом в других задачах будут другие детали, понятно что толк выделить в IMovable - всеравно остается для "универсального движения", но DIP не панацея чтобы "не менять кучу файлов" (а он для этого и задумывался первоначально имхо); но разумеется это Намного Лучше, чем держать все подтипы (GroundEnemies, FlyingEnemies, JumpingEnemies) внутри Controller и делать там switch\if логики - DIP этим поможет; * Кстати замечу что MoveParams это именно Абстракция (философская), и от нее зависят и конкретная реализация низкого уровня (GroundEnemy) и класс высокого уровня (Controller) - оба зависят от MoveParams (и оба зависят от IMovable но этот момент не столь важен в моем мысли) - главное тут то что MoveParams не является интерфейсом (как многие рекомендуют "выделять interface" и считают что этого достаточно для следования "DIP"), это именно class MoveParams, который будут использовать те, кому он нужен и как нужен (а кому не нужен - не будут использовать), со 2й часть (детали абстрации) тут может быть проблема и нарушение DIP, но важен компромисс в понимании (такую систему что я нарисовал поддерживать вполне можно, есть и другие варианты более изощренные - например как выше названные Buff \ баффы, но тут получится еще больше кода - заранее созданного, и понимаемого еще сложней, надо думать что из этого поддерживать и понимать проще).. а в видео про расширение (как ввод speed условного или damage те же специфичные только для weapon) и такие компромиссы к сожалению ничего
@sergeykazantsev1655
@sergeykazantsev1655 Жыл бұрын
Алексей, спасибо за такой комментарий, хоть его и очень сложно читать за счёт отсутствия разбиения текста. Частично с вашими доводами согласен, но в моём видео не было задачи написать идеальный код, по всем правилам DI, всё заоптимизорвать. Моя задача была наглядно донести разницу между подходами с инверсией зависимости и без неё. Понятное дело, что и коэффициенты и сами сущности можно было завернуть. Если у вас есть опыт разработки, а похоже что есть, я думаю вы сами знаете что этим можно заниматься бесконечно. Повторюсь - моя цель: наглядность для новичков, которые осваивают этот принцип впервые. На комментарий которое есть в этом видео с претензией я так же ответил. Если же вы считаете, что видео должно "лучше раскрыть те или иные темы" - вы всегда можете записать своё видео так как вы считаете нужным. Ру сегменту не хватает хороших видосиков, думаю все будут только благодарны.
@ivanatroshchenko5310
@ivanatroshchenko5310 7 ай бұрын
Ну так если нам надо впихнуть коэффициент - мы меняем интерфейс) абстракция зависит от деталей. А если нет - значит мы неправильно спроектировали предметную область. Либо пример плохой либо это просто не работает) Чем больше читаю про солид тем больше сомневаюсь в состоятельности этой идеи
@sergeykazantsev1655
@sergeykazantsev1655 5 ай бұрын
Я долго думал над тем, что данный пример недостаточно прозрачный и пришёл к новому решению, которое планирую показать в одном из ближайших видео. Идея ООП и солида всё ещё состоятельна на мой взгляд. Если любопытно, можете написать мне в тг, я расскажу про новый пример)
@TheKaazus
@TheKaazus Ай бұрын
Странный пример выбрал автор, сразу нарушив принцип O (The Open Closed Principle). Раз уж на то пошло MovementController должен принимать коллекцию экземпляров типа IMoveble.
@sergeykazantsev1655
@sergeykazantsev1655 Ай бұрын
Претензию про коллекцию еще могу понять, а где с вашей точки зрения OCP нарушается?
@ktotakoi6037
@ktotakoi6037 9 ай бұрын
пример не очень удачный, получается будто бы интерфейс просто лишняя простыня между юнитами и контроллером. Может быть стоило для замедления сделать еще одну реализацию интерфейса?
@sergeykazantsev1655
@sergeykazantsev1655 9 ай бұрын
Вся идея DIP и организации кода на уровне абстракций заключается именно в том, чтобы мы могли работать с объектами, игнорируя их конкретные детали. Для этого и нужен интерфейс. Если у вас есть идеи как сделать пример удачнее или другой пример который лучше раскроет все тонкости - с интересом ознакомлюсь. На идеальность примера не претендую
@johancrysler
@johancrysler 4 ай бұрын
Не совсем понял в каких взаимоотношениях находятся детали и классы низкого уровня в последней схеме. Там специально стрелка другой формы?
@sergeykazantsev1655
@sergeykazantsev1655 4 ай бұрын
Классы низкого уровня содержат в себе детали, эта стрелочка композиции. Это как в примере с машинами - конкретная машина может содержать конкретную уникальную деталь.
@sergeykazantsev1655
@sergeykazantsev1655 4 ай бұрын
Вообще наверное UML схему неправильно было на этом слайде делать потому что как я понимаю детали зависят от абстракции косвенно, а не напрямую. Надо будет подумать
@temych_v_gorode
@temych_v_gorode 4 ай бұрын
А вот допустим если у одного и того же метода разные аргументы(для каждого класса разные), но через init устанавливать не вариант, так как значения аргументов могут быть разными в зависимости от состояния игры, то как тогда быть?
@sergeykazantsev1655
@sergeykazantsev1655 4 ай бұрын
Тогда видимо в Init(а скорее всего лучше даже в конструктор) надо прокидывать систему где как раз хранится текущее значение динамических аргументов
@temych_v_gorode
@temych_v_gorode 4 ай бұрын
@@sergeykazantsev1655но если к примеру аргумент - это просто строка, то нету же смысла создавать систему(класс) для одной строки.
@temych_v_gorode
@temych_v_gorode 4 ай бұрын
Но если аргументом для метода производного класса будет одна строка, не создавать же класс для хранения с одной строчкой?
@temych_v_gorode
@temych_v_gorode 4 ай бұрын
У меня лично это методы Display, но один показывает количество монет, другой активные кнопки, третий карточки в магазине и для всех 3 методов нужны разные данные.
@sergeykazantsev1655
@sergeykazantsev1655 4 ай бұрын
Для отображения монет и логики отображения UI я не использую особо абстракции и производные классы. У меня есть несколько открытых проектов, которые я на гит выложил, VerticalScrollerExample, например, там можно посмотреть как я реализовал отображение счёта и жизней. Там немного по другому это делается, но может поможет. github.com/Haywaar/VerticalScrollerExample
@slava8475
@slava8475 Жыл бұрын
Я честно говоря все равно не понял. Почему во втором случае класс контроллера не зависит от деталей, ведь коэфф. замедления надо будет сэтить в контроллере. То есть как и в первом случае, надо менять код контроллера.
@sergeykazantsev1655
@sergeykazantsev1655 Жыл бұрын
Коэф замедления не обязательно сэтить в контроллере. Это надо делать в другом месте. Контроллер предназначен для передвижения всех объектов, а не инициации каждого из объекта. На 08:15 я как раз показываю как запихнуть коэфф. замедления так, чтобы контроллер от этого не пострадал :)
@slava8475
@slava8475 Жыл бұрын
Та вот только хотел писать, что надо в отдельном классе сетить)
@slava8475
@slava8475 Жыл бұрын
А во втором решении, получается, что надо будет поменять не только одну реализацию, а контроллер и остальные две реализации, а это даже хуже, чем предыдущая проблема. То есть замедление, в этом случае, это уже не деталь получается, а часть абстракции. Правильно?
@sergeykazantsev1655
@sergeykazantsev1655 Жыл бұрын
Если под вторым решением подразумевается добавление коэффициента в интерфейс, да, надо будет поменять контроллер и две реализации. Это не будет хуже, если геймплей нашей игры для всех врагов завязан на коэф замедления. Абстракция, как я и говорил, меняется редко, а детали часто. Поэтому да, может разово придётся переделать абстракцию и кучу всего поменять, но в долгосрочной перспективе(правок через 10-20) это будет выгоднее чем при изменении КАЖДОЙ детали - менять контроллер
@danilazakharov4034
@danilazakharov4034 Жыл бұрын
Тоже возник подобный вопрос, притом, до сих пор не понимаю, как его решить. По идее, мы не можем задать коэффициент замедление, так как MovementController работает с абстракцией IMovable, а с GroundEnemy. Значит, получается 2 выхода: 1) Задавать коэффициент в другом месте. Но по идее, где его ещё задавать, как не в специально для этого созданном MovementController 2) скастовать IMovable as GroundEnemy. Но этот вариант мне ещё меньше нравится, появляется внутреннее ощущение какой-то костыльности и что по-хорошему так не надо делать. Есть ли нормальный выход из этой дилеммы? Немного подумал и вывел общий вопрос, который не могу понять в DIP. Что делать, если классы высокого уровня по смыслу все-таки должны менять детали?
@belarus_by2089
@belarus_by2089 6 ай бұрын
Спасибо за объяснение, одно из лучших, если не самое!
Comfortable 🤣 #comedy #funny
00:34
Micky Makeover
Рет қаралды 16 МЛН
Schoolboy - Часть 2
00:12
⚡️КАН АНДРЕЙ⚡️
Рет қаралды 16 МЛН
Little brothers couldn't stay calm when they noticed a bin lorry #shorts
00:32
Fabiosa Best Lifehacks
Рет қаралды 17 МЛН
Принцип инверсии зависимости - SOLID в деталях
9:29
Уголок сельского джависта
Рет қаралды 2,9 М.
Dependency Inversion || storage package
10:02
АйТи Синяк
Рет қаралды 15 М.
Принцип открытости/закрытости. SOLID для React
14:51
Михаил Непомнящий
Рет қаралды 14 М.
Service Locator, Паттерны на практике, Unity, C#
12:08
Comfortable 🤣 #comedy #funny
00:34
Micky Makeover
Рет қаралды 16 МЛН