У Microsoft.Xna.Framework.Game
класса есть свойство Services, которое позволяет программисту добавлять сервис в свою игру, предоставляя тип класса и экземпляр класса методу Add.
Теперь вместо того, чтобы передавать AudioComponent
все классы и методы, которые в этом нуждаются, вы просто передаете свой Game
экземпляр и ищите сервис. ( Сервисный Локатор )
Теперь, поскольку в играх много сервисов (GraphicsDevice, SceneGraph, AudioComponent, EffectsManager и т. Д.), Теперь вы будете в основном передавать Game всем.
Так почему бы просто не сделать эти экземпляры Singleton? Ну, потому что Singletons плохи, потому что они имеют глобальное состояние, предотвращают тестирование и делают ваш дизайн намного более хрупким. Локаторы сервисов в равной степени считаются антишаблоном для многих, поскольку вместо простой передачи зависимости объекту вы передаете локатор сервисов (игру), который связывает этот класс с остальными сервисами.
Итак, почему Услуги рекомендуются в XNA и разработке игр? Не потому ли, что игры отличаются от обычных программ и тесно переплетены со своими компонентами, а необходимость проходить через каждый компонент, необходимый для функционирования класса, была бы весьма обременительной? Являются ли Game Services именно тогда необходимым злом в игровом дизайне? Существуют ли альтернативы, которые не включают длинные списки параметров и связь?
источник
Ответы:
Я не думаю, что все согласны с тем, что сервисные локаторы плохие. Локаторы сервисов предоставляют способ отделить важные функциональные возможности, которые нужны каждому от их фактической реализации. Локаторы сервисов также позволяют менять сервисы во время выполнения. Кроме того, я не думаю, что это правда, что вам нужно распространять сервисный локатор повсюду. Я думаю, что вы можете получить доступ к нему отовсюду. В то время как игровой класс с глобальными переменными должен проходить около тысячи раз за кадр (что может привести к плохой производительности).
Чтобы немного отличить локатор службы от класса с глобальными переменными, рассмотрим следующий пример:
Я создаю игру и использую объект класса gameA, который имеет глобальную переменную: загрузчик контента. Теперь в моей следующей игре я не хочу использовать класс gameA, а создаю новый класс gameB. Теперь я должен снова добавить глобалы gameA к gameB, что является дополнительной работой. Также становится трудно настроить тип загрузчика контента, который я хочу. Скажем, у меня есть игра, которая работает как на ПК, так и на XBOX. На ПК я хочу загрузчик контента, который также может открыть диалоговое окно «Открыть файл». В то время как на XBOX я определенно не хочу этого. Имея файл конфигурации, я могу даже на полпути через игру легко изменить загрузчик контента, даже где-то еще, кроме класса gameA, не делая общедоступными глобальные переменные в игре.
Теперь подумайте, я использую сервисный локатор. Я всегда могу продолжать использовать это. И даже какие услуги там могут быть разными все время. Также верно, что я даже не буду заботиться об их реализации, если у них общий интерфейс. (Хотя я мог бы использовать это и в классе, подобном gamA).
В любом случае, я думаю, что вы найдете игровые сервисы довольно удобными. Все, кого я знаю, используют это. Чтобы помочь вам немного больше. Я создал небольшой вспомогательный класс для игровых сервисов, чтобы вы могли все время выполнять кастинг: http://roy-t.nl/index.php/2010/08/25/xna-accessing-contentmanager -and-graphicsdevice-везде-в-любом-время-сервис-контейнер / Я использую его довольно часто.
источник
return (T)Instance.GetService(typeof(T));
.Service
суффикс в конце каждого метода.AddService
метод Services принимает тип, заключается в том, что вы можете указать интерфейс службы. Например,Services.AddService(typeof(IGraphicsDeviceManager), graphics);
. Затем при получении сервиса вы можете указать интерфейс в качестве типа и привести его к выбранному вами подклассу.Синглтоны обычно берут много полезных черт и объединяют их в ужасный гибрид, который дает вам несколько вещей, которые вы не хотите, наряду с тем, что вам нужно. (Это были характеристики «создания по требованию»? Глобальный охват? Обеспечение исполнения хотя бы одного экземпляра? Запрещение нескольких экземпляров?)
Вы не можете избежать сцепления полностью. Вещи используют другие вещи, и без этого ваша программа ничего не делает. Так что единственный реальный вопрос - на каком уровне абстракции он находится.
В большинстве текстов об объектной ориентации проводится различие между Композицией и Агрегацией. Важно знать концептуальную разницу между тем, что у вас есть, и тем, о чем вы знаете. К сожалению, большинство современных языков не имеют здесь четкого различия, и ссылка на объект может означать любую из этих вещей. (По иронии судьбы, C ++ делает лучше, если вы используете различные типы умных указателей.)
Один из способов , в которых вы можете сделать композицию и агрегации ясно в вашем коде является использование услуг для агрегированных объектов. Сервисы - это один из способов предоставления доступа к вещам, которыми вы не владеете, но которые вы можете использовать.
Я не думаю, что они универсально рекомендуются при разработке игр.
источник