Шина событий (Event Bus). Unity
HTML-код
- Опубликовано: 4 окт 2024
- #events #unity
Фикс ошибки ниже !
Система событий в unity с использованием шины событий (event bus)
При создании видео немного не досмотрел и допустил пару ошибок
1. Забыл добавить оператор НЕ (!) в условии в методе Unregister
!_receiverHashToReference.ContainsKey(receiverHash)
2. Из-за дублирования хэш кодов отписка на самом деле не происходила. Спасибо комментарию от пользователя [hang du]
Код с исправленной версией можно найти тут:
github.com/Lek...
Спасибо всем, кто смотрит и, тем более, проверят код из видео !
I dont understand anything but your code looks cleaner and better than most of the code i see from people in my country.
Спасибо за такой контент, редко встретишь на ютубе людей, которые умеют нормально рассказать про проектирование. Желаю развития каналу и жду новых видео!
Спасибо !
Невероятный канал, выражаю благодарность автору и желаю успеха!
Этот event bus проклятый service locator!!! Спасибо за видео))0)
Ну она не выдает инстансы объектов по запросу и служит для передачи эвентов. А вот вопрос как прокидывать зависимости в нее и на нее, какие события нужно там создавать и прочие моменты уже лежат на плечах разработчика. Хотя, конечно, event bus дает возможность творить фигню. Но как инструмент, которые решает конкретную задачу, вполне себе норм.
@@leksaysdevelopment7423 вместо того, чтобы выдавать любые сервисы, выдает любые ивенты, а так одно и то же
Я щас на первой минуте (уже на третьей) сижу, и мне интересно. А как event bus решает проблему удобочитаемости, если ничего концептуально не изменилось? Мы понять кто подписался на C# событие никак не можем, можем жмакнуть Shift + f12 и так узнать но это не решение. Event Bus даёт нам совершенно тоже самое, сущность которую мы имеем на которую могут подписываться и мы хз кто подписывается (т.е. чтобы понять кто подписался мы идём shift + f12 в шину и там shift + f12 на метод subscribe чтобы знать кто это был). Соответственно пользователи шины тоже хз на кого они подписываются включая источника сообщений хз кому он отправляет сообщения. Это плохая идея в ООП потому что: контракт отправителя сообщения, роль отправителя в системе становится неявным для пользователей, сложно прочесть из точки вызова события кого он там триггерит
А как вы предложили бы сделать? Просто, критика справедлива, однако, без альтернативного решения, она не полна)
У Макса Крюкова как-то проще все, субъективно... Спасибо за контент)
Это смотря какой видос )
Красиво
Ты сказал что обычные события неудобно дебажить и этому поможет event bus, но по ощущениям если бы ты сам им пользовался то понял бы что он только все усложняет)
Ну тут, наверное, дело вкуса. Мне не очень прикольно, когда у меня на какой-то объект 100500 зависимостей в инспекторе или через конструктор прокидывается. Количество кода в одном классе сильно увеличивается и нужно четко прослеживать связь. С шиной же мне удобнее, т.к. я под каждый тип события создаю нужную структуру и пользуюсь. По юзингам можно разобрать что и где. И тут нужно понимать, что я не призываю абсолютно все покрывать шиной. Если так делать то да, можно утонуть в разных шиновых событиях . Тут, как и везде, нужно думать, для чего применять шину, а где можно обычными событиями обойтись.
@@leksaysdevelopment7423 у тебя не будет 100500 зависимостей, у тебя будет только ссылка на объект, который вызывает ивент. А то, что ты сделал в видео - это очередной сервис локатор
Сначала было ничего не понятно, потом стало еще более не понятно, а потом когда код начал писать, осознал что это =D
Если честно, выглядит этот паттерн так, что им можно наоборот только сильнее запутать/запутаться. Но преймущества очевидны и их больше, чем неудобство оформления. Я думаю, если покумекать, то можно найти более универсальное и приемлемое решение для подобного паттерна.
I have found an issue with the code in the video: the UnRegister() function doesn't seem to work. After investigation, I discovered that the reason for this is a duplicate HashCode, which is causing the previously registered event to be overwritten. Could you please let me know if I made any mistakes?
Thanks for pointing out the problems in the code ! I added the corrected version to the description under the video
@@leksaysdevelopment7423 I appreciate your thoughtful reply. Your video is excellent and I can tell that you put a lot of effort into it. It was very informative and helpful. Thank you so much!
@@leksaysdevelopment7423 Ошибка не исправлена, так как в целом нельзя использовать GetHashCode() как уникальный ключ (один-к-одному). То есть, если попытаться зарегистрировать два разных получателя событий, у которых будет одинаковый hash code, то второй получатель не будет зарегистрирован. Для исправления необходимо объявить private Dictionary _receiverHashToReference и доработать Register() и Unregister()
@@HizusHiz Действительно, может получиться так, что мы получим коллизию хэшей. И это привет к замене одного ресивера на другого. Но, если использовать предложенное вами решение, то для каждого варианта хэша нужно создавать массив. С учетом, что хэши совпадают довольно редко, наверное, это будет несколько лишним. Если проблема заключается в том, что каждому ресиверу нужен свой уникальный Id, то можно просто использовать Guid. Поэтому, я, наверное, буду использовать строку гуида в качестве ключа. Свое решение залил на гит. Если будут какие-то дополнения, буду рад новым комментам.
Спасибо что обратили внимание на эту проблему !
Как быть если у вас есть несколько экземпляров RedEvent и нужно подписаться на события конкретного экземпляра?
Было бы не плохо рассказать почему BusHolder - это плохо в этом случае... Из за стадии инициализации? Или вообще из за его наличия, не понятно 😅
Порядок инициализации, жизненные циклы монобехов, большое количество прямых зависимостей на холдера и неудобство работы. Мне кажется, что Event Bus лучше инициализровать отдельно и сделать его сервисом. А ссылку в объектах получать из какого-нибудь DiContainer'а.
Есть еще подход с глобальным Event Bus'ом, доступ к которому через синглтон организовывается. Но при таком подходе тоже есть свои нюансы.
объяснение ужасное
Про отписку.
Сейчас же модно делать как-то так:
interface IEventBus
{
IDisposable Subscribe(IHandler handler)
}
class Unsubscriber : IDisposable
{
Action _usubscribe;
public void Dispose();
// ну и там где-нибудь Dispose-паттерн
}
Не хочется весь листинг фигачить, но суть я думаю ясна. Шина, возвращает отписчика. Тот кто подписался - может при вызове Dispose автоматом отписываться.