На собеседовании нас просят рассказать о каждом из них, правильно расположив стрелочки на схеме взаимодействия классов.
Но если отбросить всю эту теорию, смысл у них один - разделить ответственность между слоями кода.
И в этом посте я раскрою этот смысл, чтобы стало понятно зачем использовать эти паттерны, без необходимости запоминать куда стрелочки на схеме смотрят.
Принцип, из которого выросли все MV*
Любой UI или игровой экран можно разложить на три слоя:
1. Бизнес-логика (Model) - хранит и обрабатывает данные.
Пример: здоровье персонажа, инвентарь, внутренняя экономика.
2. Презентация (View) - показывает игроку информацию.
Пример: полоска HP, надписи, окна, анимации.
3. Связующее звено (Controller / Presenter / ViewModel) - решает, когда и что обновить.
Главная идея MV* - разные причины для изменений должны быть в разных местах.
Так, если мы поменяем бизнес-логику, то не придётся изменять код UI.
И наоборот - сменили виджет отображения UI (с текстового поля со значением процентов на полоску здоровья с конкретными значениями) - вся игровая логика здоровья осталась нетронутой.
Пример без разделения:
public class Health : MonoBehaviour
{
[SerializeField] private TMP_Text _text;
[SerializeField] private Image _bar;
private float _hp = 100;
public void TakeDamage(float dmg)
{
_hp -= dmg;
_text.SetText($"{_hp}");
_bar.fillAmount = _hp / 100;
}
}
Пока одна панель - всё ок.
Но потом приходит геймдизайнер и говорит:
“Добавь полоску над персонажем и окно статистики.”
И ты полностью переписываешь компонент, уничтожая старую логику.
Каждое новое изменение = переписывание и логики хп, и его отображения.
Чтобы избежать постоянного переписывания UI кода, необходимо создать:
1. HealthModel, в которой будет находиться бизнес-логика
2. HealthView, который будет заниматься отображением (UI)
3. HealthPresenter, который связывает Model и View. Например, просто слушает события из Model и вызывает методы по обновлению View
В таком случае, если хочешь добавить вторую полоску здоровья - просто сделай второй HealthView и подпиши его на ту же модель.
Старый код останется полезным, и его можно будет использовать для других задач.
Посмотреть изменённый код можно тут
Смысл, который стоит запомнить
MV* - паттерн не ради паттерна.
Он необходим, чтобы изолировать причины изменений и отображение изменений.
И когда завтра геймдизайнер захочет 3 разных шкалы HP, ты просто подключишь новые View — без изменения логики HP и переписывания старого кода View.
🚀 Пост Guru Unity: @Minerope
