Пример:
User имеет поведение:
- changeName(newName) — меняем имя
- activate() — активируем (меняется статус с првоеркой, не заблокрирвоан ли к примеру или еще что-то)
- changeEmail(newEmail)
Синопсис:
Все изменения можем смотреть у объекта (например геттеры) — вызывать состояние объекта и сравнивать со старым, предварительно зная старый
Но можем испускать события — User копит таковые в некотором внутрнеем массиве domainEvents, все важные изменения там и пишутся
Потом просто выше по коду попросить у объекта "дай-ка события, которые есть,
Например методом raiseEvents() мы получим события об изменении состояний/активации/смены имени/смена токенов
Архитектурно это может быть не метод raiseEvents(), а какой-нибудь observable (если у нас реактивная модель) и просто подписку повесить с обработчиком стрима, а можем просто вызвать метод получения
далее с этими событиями работать
Чтобы в коде не явно все состояния отслеживать, а отслеживать динамически через одну точку испускания событий и в приложении навешивать обработчики (например для генерации отчетов, логов изменений, навесить логику постобработки)
События могут быть не доменные (не как выше пример с доменным объектом), а события приложения/сервисной службы... Например есть юзкейс о регистрации, в приложении у вас есть эвент-дисптечер, при регистрации пользователя после корректного завершения через диспетчер кидаете событие и приложение как-то его обрабатывает внутри, вызывая обработчики события — это позволяет понизить связаность в системе: вам не нужно явно вызывать логику по месту регистрации пользователя, а просто зарегистрировать обработчик (указать, на какие события ему реагировать)
Есть событие, есть обработчик, нужно новое поведение навесить — регистрируете еще обработчик и делаете в ней логику, которая нужна, сам код регистрации пользователя остется не тронутым (вспоминанем вясокую связанность, так вот — мы не завязаны на код этой самой регистрации)
События в этом случае являются средством управления IoC (инверсия контроля кода)