Внедрение зависимостей и производительность разработки

Резюме

В течение последних нескольких месяцев я программировал легкий игровой движок на основе C #с абстракцией API и системой сущностей/компонентов/скриптов.. Вся его идея состоит в том, чтобы упростить процесс разработки игр в XNA, SlimDX и т. д., предоставляя архитектуру, аналогичную той, что используется в движке Unity.

Проблемы дизайна

Как известно большинству разработчиков игр, существует множество различных сервисов, к которым нужно обращаться по всему коду.Многие разработчики прибегают к использованию глобальных статических экземпляров, например. Менеджер рендеринга (или композитор ), Сцена, Графическое устройство (DX ), Регистратор, Состояние ввода, Область просмотра, Окно и так далее. Есть несколько альтернативных подходов к глобальным статическим экземплярам/одиночкам. Один из них — предоставить каждому классу экземпляр классов, к которым ему нужен доступ, либо через конструктор, либо через внедрение зависимостей конструктора/свойства (DI ), другой — использовать глобальный локатор службы, такой как ObjectFactory StructureMap, где локатор службы обычно настраивается как контейнер IoC.

Внедрение зависимостей

Я выбрал DI по многим причинам. Наиболее очевидным из них является тестируемость за счет программирования для интерфейсов и наличия всех зависимостей каждого класса, предоставляемых им через конструктор. Эти классы легко тестируются, поскольку тестовый контейнер может создавать экземпляры необходимых служб или их макеты и подавать в каждый класс для тестирования. Еще одной причиной использования DI/IoC было, хотите верьте, хотите нет, повысить читабельность кода. Больше нет громоздкого процесса инициализации, когда создаются экземпляры всех различных сервисов и вручную создаются экземпляры классов со ссылками на требуемые сервисы. Настройка ядра (NInject )/Registry (StructureMap )удобно предоставляет единую точку конфигурации для движка/игры, где выбираются и настраиваются реализации сервисов.

Мои проблемы

  • Мне часто кажется, что я создаю интерфейсы ради самих интерфейсов
  • Моя продуктивность резко упала, так как все, что я делаю, это беспокоюсь о том, как делать что-то в стиле DI, -вместо быстрого и простой глобальный статический способ.
  • В некоторых случаях, например. при создании экземпляров новых сущностей во время выполнения требуется доступ к контейнеру/ядру IoC для создания экземпляра. Это создает зависимость от самого контейнера IoC(ObjectFactory в SM, экземпляра ядра в Ninject ),что действительно идет вразрез с причиной использования одного в первую очередь. Как это можно решить? На ум приходят абстрактные фабрики, но это еще больше усложняет код.
  • В зависимости от требований службы конструкторы некоторых классов могут стать очень большими, что сделает класс совершенно бесполезным в других контекстах, где и если IoC не используется.

В основном выполнение DI/IoC резко снижает мою производительность и в некоторых случаях еще больше усложняет код и архитектуру. Поэтому я не уверен, должен ли я следовать этому пути или просто сдаюсь и делаю все по старинке. Я не ищу единого ответа, говорящего, что я должен или не должен делать, но обсуждение того, стоит ли использовать DI в долгосрочной перспективе, в отличие от использования глобального статического/одиночного способа, возможные плюсы и минусы, которые я упустил из виду, и возможные решения моих проблем, перечисленных выше, при работе с DI.

11
задан Steven 8 March 2017 в 13:03
поделиться