Рефакторинг Unity C#: 500₽ кода — до и после

Заказанный на сомнительной бирже код, стоивший 500 рублей, демонстрирует крайне низкое качество. Этот пример наглядно показывает необходимость рефакторинга даже в работающем коде. Представлены исходный и рефакторированный код классов Cube и CubeManager.

Анализ исходного кода: Класс Cube

Исходный код содержит два класса: Cube и CubeManager. Класс Cube отвечает за управление отдельным кубом, атакующим противника. Кубы разбросаны на сцене и сражаются парами. Класс управляет перемещением и нанесением урона.

Предполагается наличие полей health (здоровье) и cooldown (время перезарядки). Поле cube2 хранит ссылку на противника. Использование публичных полей (health, cooldown, cube2) является грубым нарушением принципов ООП. Несогласованность в стиле именования полей (одно с большой, другое с маленькой буквы) ухудшает читаемость. Имя поля cube2 неинформативно. Метод Start содержит стандартные, бесполезные комментарии.

Метод Update, выполняемый каждый кадр, включает отсчёт кулдауна, проверку дистанции до противника (transform.Translate) с использованием магического числа 0.1 (расстояние в метрах). Нарушена стилистика кода: в одних блоках if используются фигурные скобки, в других — нет. Отступы отсутствуют. Перемещение происходит только при дистанции до противника больше единицы. Проверка кулдауна, его сброс и изменение здоровья противника (health) осуществляется через прямой доступ к публичному полю, что нарушает инкапсуляцию. Отсутствие контроля объекта над собственным здоровьем приводит к проверке здоровья в каждом кадре для уничтожения объекта при нулевом значении. Качество кода не соответствует даже уровню junior-разработчика.

Анализ исходного кода: Класс CubeManager

Класс CubeManager хранит всё состояние в методе Update. Поиск ближайшего свободного противника и назначение пар для битвы реализованы с помощью двух вложенных циклов и неудачного именования переменных. Поиск всех объектов осуществляется каждый кадр, что значительно снижает производительность. Связь между строками кода трудно проследить.

Рефакторинг кода: Класс Cube

Рефакторинг класса Cube включает:

  • Перевод полей health и cooldown в приватные с префиксом _ (_health, _cooldown).
  • Переименование поля cube2 в _target.
  • Создание метода TakeDamage для нанесения урона с проверкой на отрицательный урон.
  • Перемещение проверки здоровья в метод TakeDamage.
  • Добавление фигурных скобок к блокам if.
  • Вынесение магического числа в поле.
  • Изменение порядка строк в Update для повышения читаемости.
  • Передачу ссылки на компонент и вызов метода TakeDamage вместо использования GetComponent.
  • Разделение метода Update на части: таймер, проверка состояния, движение и атака.

Рефакторинг кода: Класс CubeManager

Рефакторинг класса CubeManager:

  • Замена GameObject.FindGameObjectsWithTag на список кубов.
  • Использование FindObjectsOfType для поиска объектов по типу.
  • Создание свойства FreeCubes для хранения списка свободных кубов.
  • Перебор свободных кубов в методе Update.
  • Создание метода FindClosestCube для поиска ближайшего противника с проверкой на то, что куб не является самим собой.
  • Добавление обработчика события смерти куба (OnCubeDeath) для удаления куба из списка FreeCubes.
  • Добавление обработчика события OnDestroy для удаления подписки на событие OnCubeDeath.

Завершение рефакторинга

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

Что будем искать? Например,программа