Рефакторинг с уходом от императива к декларативу.

insert_comment 0
visibility 193
|
07.08.2020

В прошлом посте мы делали условия на основе иерархии типов. Там пример был честно говоря натянутый, хоть и приколдесный. Данная техника может применяться в разных условиях, но когда у нас уже есть определённые типы мы можем сделать кое, что другое. И сейчас я это покажу.

Напоминаю что мы получили такой код:

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 курсов бесплатно

Начните карьеру разработчика игр бесплатно!


    Комментарии


    Отзывы