Рефакторинг с уходом от императива к декларативу.
В прошлом посте мы делали условия на основе иерархии типов. Там пример был честно говоря натянутый, хоть и приколдесный. Данная техника может применяться в разных условиях, но когда у нас уже есть определённые типы мы можем сделать кое, что другое. И сейчас я это покажу.
Напоминаю что мы получили такой код:
if (enteredObject.Is<Bicycle>().Or<Soldier>().Or<Car>())
{
Console.WriteLine(true);
}
Какие у него проблемы? Мы описали правило, что только мотоцикл, солдат или машина может завершить игру при входе в триггер.
В случае если у нас этот список расшириться нам придётся искать точки где есть такая обработка.
Это проблема можно легко решить вынеся проверку в предикат. Банально в функцию которая бы сообщила подходит объект или нет. Сейчас по условию у нас этот код просто размещается в обработчики вхождения в триггер.
С помощью метода расширения мы могли бы расширить например тип GameObject и получить такой код:
public static bool CanFinishGame(this GameObject gameObject)
{
var presenter = gameObject.GetComponent<IPlayerPresenter>();
if (presenter == null)
return false;
return presenter.Is<Bicycle>().Or<Soldier>().Or<Car>();
}
Таким образом наши пляски мы согласуем в одном методе и в дальнейшем можно будет его использовать.
Мы можем зайти в этом коде с другого края. Не в нашем коде размечать типы которые могут или не могут завершать игру, а дать такую возможность другой части системы сделать это за нас.
Например у нас есть ядро игры которое мы описали и есть отдельная часть которая описывает различные геймплейные механики. В таком случае при добавление презентеров нам хотелось бы, чтобы разработчики могли самостоятельно пометить тип не влезая в код ядра.
Вот тут интересно.
Возьмём A и B. A - код проверки а B иеерархия типов.
Если A это фреймворк а B это некий домейный код, то очень комфортно применять способ который я сейчас опишу так, как по куче причин мы не можем изменять фреймворк (он может быть банально скомпилирован в библиотеку). Т.е мы можем вносить изменения в иеерархию типов но не можем трогать код проверки.
А если мы не можем менять код иеерархии а можем только код проверки то нам остаётся первый способ и различные хитрости чтобы это было комфортно.
Например проверка проводится по встроенным в Unity компонентам которые мы изменять не можем или же типы из какого-то ассета и трогать их тоже нельзя.
Теперь перейдём к варианту когда мы хотим записать проверку, запретит её изменение и в дальнейшем оперировать только иеерархией.
В таком случае мы можем применить аттрибуты.
Выглядит это так:
[GameFinisher]
class Bicycle : IPlayerPresenter { }
[GameFinisher]
class Soldier : IPlayerPresenter { }
[GameFinisher]
class Car : IPlayerPresenter { }
class Helicopter : IPlayerPresenter { }
Т.е при добавление типа мы можем добавить к нему наш аттрибут. И теперь осталось только переписать проверку.
return presenter.GetType()
.GetCustomAttributes(typeof(GameFinisherAttribute), true).Length > 0;
Можно с помощью метода расширения сократить до:
presenter.GetType().HasAttribute<GameFinisherAttribute>();
Если хотите регулярно видеть такие рефакторинги то становитесь донном нашего сообщества! Для платны подписчиков я пару раз в неделю публикую такие разбор.
Если хотите писать такой же код то записывайтесь на мой курс для профессионалов - http://ijunior.ru/csharp-medium?utm_source=vk&utm_medium=article&utm_campaign=ijunior&utm_term=AttributesExample
7 курсов бесплатно
Начните карьеру разработчика игр бесплатно!
Вы также можете написать нам сами на почту: romaan27@gmail.com
Вы также можете написать нам сами на почту: romaan27@gmail.com
Программист, разработчик игр, писатель.
Мой канал на YouTube
unity
- 11 проектов в портфолио
- Гарантия трудоустройства
- Поддержка менторов
Р7500
7500
В месяц