Отличное видео. До этого сталкивался с непониманием проблемы, которую решает этот принцип. Спасибо за объяснение, теперь понимаю. Хотелось бы увидеть, как ты реализовал контекстное меню с действиями у разных предметов. Сам столкнулся с такой трудностью. Немного не понимаю, как обрабатывать в ui при наведении на разные предметы разные кнопки.
Спасибо, у меня есть планы написать вторую игру в рубрике "паттерны на практике". Там я хочу как раз сфокусироваться на сложных диалогах и предметах которые усиляют игрока. Всё это конечно потребует времени, но буду стараться)
Появился небольшой диссонанс от нескольких принципов, кажется будто они немного противоречат друг другу. Вот у нас есть Item, Sword, HealthPotion и мы хотим добавить Junk. Когда мы оставляем пустой метод Use, мы нарушаем LSP, но при этом соблюдаем OCP (не изменили базовый, поменяли поведение производного). Когда выводим Use в отдельный интерфейс, то смогли соблюсти LSP, но полностью похерили OCP, изменив базовый класс. Получается, тут дело в том, что нам изначально нужно было писать, чтобы не нарушить оба этих принципа? Но разве такое вообще возможно предугадать на 100%, что в будущем потребуется поменять, а что нет? P.S. Ну и пользуясь случаем, хотел сказать спасибо за уроки) Отличная подача, прекрасное объяснение материала и грамотно подобранные мемы, ну красотища
Я считаю что OCP не противоречит принципу LSP. Всё как вы и сказали, хорошую архитектуру нужно стараться продумывать заранее, и пытаться предвидеть зоны для расширения. На этапе формирования архитектуры игры желательно понимать - может ли появиться новая категория предмета или нет. К тому же, OCP с моей точки зрения не жесткое правило "Не смей изменять написанный код" а скорее рекомендательная эффективная стратегия. "Вместо изменения, расширяй". В реальных проектах конечно есть место рефакторингу когда просто бульдозером перекорчёвывают несколько десятков скриптов и это совершенно нормально и такое рано или поздно случается. Так что я думаю принцип OCP можно озвучить так "Лучше расширять, чем изменять, но если уж совсем вилы, иногда приходится и изменять"
Отличное видео, хотелось бы увидеть разбор более сложных кейсов с применением интерфейсов на практике в Unity. Насколько мне известно, там довольно много подводных камней, которые делают использование интерфейсов намного менее оправданным.
Спасибо! Я подумываю над тем, чтобы сделать видео либо с конкретными задачами, упражнениями по солиду, либо с разборов каких-то кусков кода с реальных проектов. Но пока все в набросках
Отличный ролик, но я не очень понимаю как использовать этот принцип, когда в проекте много интерфейсов. Допустим у меня есть класс BaseItem с методом Collect и интерфейсы в духе IUsable, IDiscardeable, IDestroyable, ISellable и тд. Производные класса BaseItem по идее могут наследовать все эти интерфейсы разом, но как тогда их хранить? создавать по списку на каждый интерфейс? или создать один список BaseItem и при помощи if esle проверять наследуется ли экземпляр класса от нужных интерфейсов?
скажите пожалста, а как после добавления интерфейса пройтись циклом по списку ? . . . только типизировать список . . . а по-другому нельзя без ????????
на 10:03 на видео как раз это и делается. Создается три объекта разных реализаций и они добавляются в список usableItems. И потом по этому списку мы идём циклом.
вопрос такой . . . между 8:45 и 9:00 . . .цитата: "если поставить любой производный класс" . . . а куда "поставить" ? . . . тут наверное какой-то текст пропущен . . . прослушайте пожалуйста сами ваш текст
Цитата на 8:48 "И вот принцип LSP как раз говорит о том что нужно организовать архитектуру таким образом, чтобы если мы подставили ЛЮБОЙ производный класс, в том числе наш JunkItem, система должна отработать без поломок". Куда именно подставлять? Подставлять в систему где мы массово пробегаемся по предметам, причем к предметам мы обращаемся как к базовым классам. Чуть раньше в этом же видео я показывал скрипт где мы пробегались по видео (07:16 TestFirst и 08:18 TestSecond)
Можно, но нужно ли? Тут вопрос в разнице между абстрактным классом и интерфейсом. Если помимо метода Use вкупе идут какие-то параметры, то можно. А так особого смысла нет
Блять, круто конечно...Но наследник IEnumerable ICollection является родителем ReadOnlyCollection в котором поля Add и Remove заткнуты исключениями. А это, типа, стандартная логика языка и нарушается LSP( ЛСП - Ползать)
@@sergeykazantsev1655 как по мне. наоборот интереснее когда я могу что-то делать. ну на это получу какое-то забавное сообщение, чем тупо отстуствие такой возможности
Ну вы как разработчик, а скорее даже как геймдизайнер вольны выбирать как вам больше нравится. Пример я привёл в рамках своей задачи, чтобы показать что такой случай может быть когда один из производных классов не корректно отрабатывает логику указанную в базовом классе и это и есть нарушение LSP Если у вас есть более наглядный пример нарушения LSP - я готов ознакомиться, никогда не против найти вариант получше, всё таки с момента видео год прошёл)
По мне дык самый понятный принцип. Когда-то давно сам пришёл к тому что нужно соблюдать эти правила
Очень качественный видеоролик, помогает готовиться к экзаменам 👍👍
Спасибо, легко и понятно. Жаль мало просмотров для того контента.Повезло, что попало в рекомендации !
Спасибо, да этому каналу вчера 2 недели исполнилось. Постараюсь наполнить его полезными уроками, авось со временем просмотры накапают)
Первое понятное объяснение. Спасибо огромное.
я вас обожаю ❤
У меня аж флэшбэк к тем временам, когда я читал head first design patterns. Особенно про утку
Отличное видео. До этого сталкивался с непониманием проблемы, которую решает этот принцип. Спасибо за объяснение, теперь понимаю. Хотелось бы увидеть, как ты реализовал контекстное меню с действиями у разных предметов. Сам столкнулся с такой трудностью. Немного не понимаю, как обрабатывать в ui при наведении на разные предметы разные кнопки.
Спасибо, у меня есть планы написать вторую игру в рубрике "паттерны на практике". Там я хочу как раз сфокусироваться на сложных диалогах и предметах которые усиляют игрока. Всё это конечно потребует времени, но буду стараться)
Великолепные объяснения принципов. Спасибо.
очень хорошо объяснено, уверен новичкам все кристально понятно, лайк
Отличное видео! Спасибо. Вы очень хорошо и интересно доносите информацию.
Спасибо! Объясняете сильно лучше чем кто либо! Даже LSP и DIP стали понятней :)
Какой же ты крутой!
Большое спасибо за видосы, очень познавательно.
Спасибо!
Замечательный контент и канал
Круть!
Появился небольшой диссонанс от нескольких принципов, кажется будто они немного противоречат друг другу. Вот у нас есть Item, Sword, HealthPotion и мы хотим добавить Junk. Когда мы оставляем пустой метод Use, мы нарушаем LSP, но при этом соблюдаем OCP (не изменили базовый, поменяли поведение производного). Когда выводим Use в отдельный интерфейс, то смогли соблюсти LSP, но полностью похерили OCP, изменив базовый класс.
Получается, тут дело в том, что нам изначально нужно было писать, чтобы не нарушить оба этих принципа? Но разве такое вообще возможно предугадать на 100%, что в будущем потребуется поменять, а что нет?
P.S. Ну и пользуясь случаем, хотел сказать спасибо за уроки) Отличная подача, прекрасное объяснение материала и грамотно подобранные мемы, ну красотища
Я считаю что OCP не противоречит принципу LSP. Всё как вы и сказали, хорошую архитектуру нужно стараться продумывать заранее, и пытаться предвидеть зоны для расширения. На этапе формирования архитектуры игры желательно понимать - может ли появиться новая категория предмета или нет.
К тому же, OCP с моей точки зрения не жесткое правило "Не смей изменять написанный код" а скорее рекомендательная эффективная стратегия. "Вместо изменения, расширяй". В реальных проектах конечно есть место рефакторингу когда просто бульдозером перекорчёвывают несколько десятков скриптов и это совершенно нормально и такое рано или поздно случается.
Так что я думаю принцип OCP можно озвучить так "Лучше расширять, чем изменять, но если уж совсем вилы, иногда приходится и изменять"
Отличное видео, хотелось бы увидеть разбор более сложных кейсов с применением интерфейсов на практике в Unity. Насколько мне известно, там довольно много подводных камней, которые делают использование интерфейсов намного менее оправданным.
Спасибо! Я подумываю над тем, чтобы сделать видео либо с конкретными задачами, упражнениями по солиду, либо с разборов каких-то кусков кода с реальных проектов. Но пока все в набросках
Отличный ролик, но я не очень понимаю как использовать этот принцип, когда в проекте много интерфейсов. Допустим у меня есть класс BaseItem с методом Collect и интерфейсы в духе IUsable, IDiscardeable, IDestroyable, ISellable и тд. Производные класса BaseItem по идее могут наследовать все эти интерфейсы разом, но как тогда их хранить? создавать по списку на каждый интерфейс? или создать один список BaseItem и при помощи if esle проверять наследуется ли экземпляр класса от нужных интерфейсов?
Насколько я понимаю, да, создавать по списку на каждый интерфейс и создавать системы которые обрабатывают один конкретный тип
@@sergeykazantsev1655 Спасибо!
скажите пожалста, а как после добавления интерфейса пройтись циклом по списку ? . . . только типизировать список . . . а по-другому нельзя без ????????
на 10:03 на видео как раз это и делается. Создается три объекта разных реализаций и они добавляются в список usableItems. И потом по этому списку мы идём циклом.
вопрос такой . . . между 8:45 и 9:00 . . .цитата: "если поставить любой производный класс" . . . а куда "поставить" ? . . . тут наверное какой-то текст пропущен . . . прослушайте пожалуйста сами ваш текст
Цитата на 8:48 "И вот принцип LSP как раз говорит о том что нужно организовать архитектуру таким образом, чтобы если мы подставили ЛЮБОЙ производный класс, в том числе наш JunkItem, система должна отработать без поломок".
Куда именно подставлять? Подставлять в систему где мы массово пробегаемся по предметам, причем к предметам мы обращаемся как к базовым классам.
Чуть раньше в этом же видео я показывал скрипт где мы пробегались по видео (07:16 TestFirst и 08:18 TestSecond)
@@sergeykazantsev1655 спасибо . . . за цитату
а можно было вместо интерфейса сделать класс UsedItem, в него засовываем Use() из Item и уже от него наследоваться мечу и зелью?
Можно, но нужно ли? Тут вопрос в разнице между абстрактным классом и интерфейсом. Если помимо метода Use вкупе идут какие-то параметры, то можно. А так особого смысла нет
@@sergeykazantsev1655 тогда что лучше: один абстрактный класс с несколькими методами или на каждый метод по интерфейсу?
сам того не зная ISP использовал)
Типа того, да. Считаю, что правильный ответ - это поступать по ситуации. В зависимости что за поведение, есть ли какие-то свойства и тд.
@@sergeykazantsev1655 а вот это уже мидлом нужно быть, чтобы чувствовать
Блять, круто конечно...Но наследник IEnumerable ICollection является родителем ReadOnlyCollection в котором поля Add и Remove заткнуты исключениями. А это, типа, стандартная логика языка и нарушается LSP( ЛСП - Ползать)
Ну наверное read-only можно считать исключением, хотя и не буду отрицать что в некоторых случаях приходилось пренебрегать этим принципом
Что за странный пример? Use у мусорных предметов вполнее нужен. для вывода сообщение что игрок идиот
Ну это токсичненько писать игрокам что они идиоты) лучше сделать так чтобы механика use была полностью скрыта для мусорных предметов)
@@sergeykazantsev1655 как по мне. наоборот интереснее когда я могу что-то делать. ну на это получу какое-то забавное сообщение, чем тупо отстуствие такой возможности
Ну вы как разработчик, а скорее даже как геймдизайнер вольны выбирать как вам больше нравится.
Пример я привёл в рамках своей задачи, чтобы показать что такой случай может быть когда один из производных классов не корректно отрабатывает логику указанную в базовом классе и это и есть нарушение LSP
Если у вас есть более наглядный пример нарушения LSP - я готов ознакомиться, никогда не против найти вариант получше, всё таки с момента видео год прошёл)
Спасибо!