# События

У вас когда-нибудь случалось такое, что один компонент влез в зону ответственности другого? Ситуация, когда на такой компонент сваливалась вся работа и из за этого он становился перегруженным? С этим рано или поздно сталкиваются все, но не все знают, как решить эту проблему.

## Пример проблемы

Представим, что мы работаем над игрой, в которой персонаж может зарабатывать игровую валюту и тратить ее в магазине. Для этого мы сделали ему простой кошелек:

```csharp
public class Wallet : MonoBehaviour
{
    public int Money { get; private set; }
    
    public void AddMoney(int amount)
    {
        if (amount <= 0)
            return;
        
        Money += amount;
    }
    
    public bool TrySpendMoney(int amount)
    {
        if (amount <= 0)
            return;
        
        bool isEnough = Money >= amount;
        
        if (isEnough)
            Money -= amount;
        
        return isEnough;
    }
}
```

У этого кошелька одна простая ответственность: проводить транзакции и обеспечивать их корректность. Но теперь нам прислали новую задачу: отображать количество средств на экране. Не проблема, мы уже реализовали класс `WalletView`, который умеет  отображать количество средств. Осталось лишь вызвать у него метод:

```csharp
[SerializeField] private WalletView _walletView;
//...
_walletView.Display(Money);
```

Нам опять пришла новая задача! Теперь каждый раз, когда происходит транзакция, нужно сделать сохранение в файл, чтобы запомнить сколько денег теперь есть у игрока. Не проблема, мы уже реализовали класс `FileSaver`, который умеет сохранять количество денег. Нужно лишь вызвать у него метод:

```csharp
[SerializeField] private FileSaver _fileSaver;
//...
_fileSaver.SaveMoney(Money);
```

Удивительно, опять новая задача! Теперь магазин должен предлагать игроку новые товары, когда тот произвел транзакцию. Не проблема, обратимся к классу `Shop`:

<pre class="language-csharp"><code class="lang-csharp">[SerializeField] private Shop _shop;
//...
<strong>_shop.OfferItems(Money);
</strong></code></pre>

Видите, куда это идет? Вот так теперь выглядит метод `AddMoney` у кошелька:

```csharp
public void AddMoney(int amount)
{
    if (amount <= 0)
        return;
        
    Money += amount;
    
    _walletView.Display(Money);
    _fileSaver.SaveMoney(Money);
    _shop.OfferItems(Money);
}
```

Бред, так ведь? Теперь кошелек делает совершенно не свою работу. Как нам в будущем догадаться, что именно кошелек делает все это? Как понять, почему магазин внезапно перестал работать, когда мы всего лишь убрали кошелек у игрока? Как понять, почему кошелек отказывается работать, когда мы всего лишь выключили интерфейс? Много вопросов - мало ответов.

## Суть проблемы

Где в этой ситуации корень зла? Когда мы допустили роковую ошибку? Мы сделали это тогда, когда повесили на кошелек задачи других компонентов. Но как этого избежать, если только кошелек знает, что происходит с деньгами?

Например, кошелек может уведомить всех, что происходит, но не указывать компонентам, что именно делать. Тогда ответственность за реакцию компонентов переляжет с кошелька на них самих. Мысленно представим такой диалог:

{% code overflow="wrap" %}

```
- Wallet (кричит через громкоговоритель): Количество денег изменилось! Теперь у нас 50 монет. Сами решайте что делать с этим, на этом мои полномочия все.

- WalletView: Мне это важно. Выведу на экран число 50

- FileSaver: Мне это важно. Запишу в файл число 50

- PlayerMover: Меня это не беспокоит, направление движения игрока не зависит от финансового положения. Я ничего не слышал

- Shop: Мне это важно. Обновлю ассортимент товаров: добавлю те, которые можно купить за 50 монет

- Coin: Меня не интересует, сколько денег у игрока. Я ничего не слышал
```

{% endcode %}

Заметьте, как кошелек больше **не отвечает** за остальных! Он сообщил информацию и на этом успокоился. Так мы и можем решить эту проблему.

## И какое отношение к этому имеют события?

**Событие** *(англ. Event)* - это механизм, позволяющий организовать общение между компонентами описанным выше образом. Название *"Событие"* появилось, потому что сообщение, которое передает компонент, говорит, что *"что-то случилось"* или *"произошло какое-то событие"*. То есть событием называется само *"сообщение"*.

Тот компонент, который сообщает информацию через событие, называется владельцем события. Помните, как некоторые компоненты услышали сообщение, а некоторые нет? Одни называются *"слушателями"* *(англ. Listeners)* или *"подписчиками"* события, потому что они получают из него информацию. А другие никак не называются, не хотят - не слушают.

Чтобы стать слушателем события, нужно на него подписаться *(англ. Subscribe)*, а чтобы перестать быть слушателем нужно отписаться *(англ. Unsubscribe).*

## Что с этим делать дальше?

Теперь нам известно, зачем нужны события, и мы знаем основные термины. Осталось только почитать про типы событий и их синтаксис: [`UnityAction`](https://ijunior-knowledge-base.gitbook.io/baza-znanii-yayunior/unity/sobytiya/action-i-unityaction) и [`UnityEvent`](https://ijunior-knowledge-base.gitbook.io/baza-znanii-yayunior/unity/sobytiya/unityevent)
