Яка різниця між ігровими службами XNA та прославленими глобальними змінними?


10

Microsoft.Xna.Framework.GameКлас має Services властивість , яке дозволяє програмісту додати службу в свою гру, надаючи тип класу і екземпляр класу для методу Add.

Тепер, замість того, щоб передавати AudioComponentвсі класи та методи, які цього вимагають, ви просто передаєте свій Gameпримірник і шукаєте службу. ( Локатор обслуговування )

Тепер, оскільки в іграх є багато сервісів (GraphicsDevice, SceneGraph, AudioComponent, EffectsManager та ін.), Ви в основному проходите гру до всього.

То чому б просто не зробити ці екземпляри Singleton? Ну, тому що одиночні погані, оскільки вони мають глобальний стан, запобігають тестуванню та роблять ваш дизайн набагато крихкішим. Локатори сервісів для багатьох однаково вважаються анти-зразком, оскільки замість того, щоб просто передавати залежність об'єкту, ви передаєте локатор сервісу (Гра), який з'єднує цей клас з рештою сервісів.

Тож чому чомусь рекомендуються Послуги в розробці XNA та ігор? Це тому, що ігри відрізняються від звичайних програм і сильно переплітаються зі своїми компонентами, і тому, що потрібно передати кожен компонент, необхідний для функціонування класу, було б дуже громіздко? Чи ігрові послуги просто тоді є необхідним злом у дизайні ігор? Чи є альтернативи, які не включають тривалі списки параметрів та з'єднання?


3
"Локатори послуг однаково вважаються анти-зразком для багатьох" - [потрібне цитування]. Очевидно, що використовувати їх там, де вони вам не потрібні, це погано - це стосується всіх програмних конструкцій, - але я ніколи не чув, щоб локатори сервісів називали анти-шаблон. (З іншого боку, я також намагаюся уникати програмістів, які витрачають більшу частину свого часу на обговорення останніх

@JoeWreschnig, хоча я з вами згоден, я кілька копав і виявив це: blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx
Roy T.

2
Так, але той хлопець продає книгу про використання DI; Очевидно, він не хоче, щоб ти використовував щось просте, тоді ти не купиш його книги! (Якщо говорити серйозно, оригінальна стаття про Фоллера щодо DI / SL висвітлювала саме цю тему - martinfowler.com/articles/… - і щоденник цього блогу нічого не додає до обговорення.)

Я хотів би позначити це посилання, яке ви опублікували як відповідь Мартіна Фаулера (хоча це не моє запитання)
Рой Т.

Відповіді:


6

Я не думаю, що всі згодні з тим, що локатори обслуговування погані. Локатори послуг - це спосіб відокремити важливу функціональність, необхідну всім для їх реальної реалізації. Локатори сервісів також надають спосіб міняти послуги під час виконання. Крім того, я не думаю, що це правда, що вам потрібно проходити навколо локатора обслуговування скрізь. Я думаю, ви можете отримати доступ до нього звідусіль. У той час як ігровий клас з глобалами потрібно проходити близько тисячі разів за кадр (це призведе до поганої продуктивності).

Щоб зробити різницю між локатором сервісу та класом із глобалами трохи більш зрозумілим, розглянемо наступний приклад:

Я створюю гру та використовую об’єкт класу gameA, який має глобальну змінну: завантажувач вмісту. Тепер у своїй наступній грі я не хочу використовувати клас гриA, але створити новий клас гриB. Тепер мені доведеться знову додати глобальні ігри gameA до gameB, що є додатковою роботою. Також стає важко налаштувати тип завантажувача вмісту, який я хочу. Скажімо, у мене є гра, яка працює як на ПК, так і на XBOX. На ПК я хочу завантажувач вмісту, який також може відкрити діалогове вікно "відкритий файл". Хоча на XBOX, я точно цього не хочу. Маючи конфігураційний файл, я навіть можу легко змінити завантажувач вмісту навіть з іншого місця, ніж клас GameA, не роблячи глобальних гравців у гріAA загальнодоступними.

Тепер розгляньте, що я використовую сервіс-локатор. Я завжди можу продовжувати його використовувати. І навіть які саме послуги там можуть бути різними постійно. Правда, що я навіть не переймаюся їх реалізацією, якщо вони мають спільний інтерфейс. (Хоча я міг би використовувати це і в клас гри, як клас.

У будь-якому випадку, я думаю, ви знайдете ігрові послуги досить зручними. Кожен, кого я знаю, використовує. Щоб допомогти вам трохи більше. Я створив невеличкий клас помічників навколо ігрових сервісів, щоб ви могли весь час робити менше кастингу: http://roy-t.nl/index.php/2010/08/25/xna-accessing-contentmanager -і-graphicsdevice-будь-де-будь-коли-the-gameservicecontainer / я використовую його досить багато.


Дякую за відповідь. У класі, який потребує послуги, зазвичай ви просто запитуєте клас GameServices для послуги, коли це потрібно, або ви створюєте змінну члена в класі та запитуєте послугу лише у конструкторі? Я гадаю, що я прошу, як це повільно return (T)Instance.GetService(typeof(T));.
Джон Поллик

Крім того, що ви думаєте про цю реалізацію класу GameServices? Я видалив зайвий сингтон, тому що він не мав жодних особливостей, яких абстракція ще не мала. Також я видалив зайвий Serviceсуфікс наприкінці кожного методу.
Джон Поллик

Крім того, я вважаю, що причина в тому, що AddServiceметод Services приймає тип, полягає в тому, що ви можете вказати інтерфейс служби. Наприклад, Services.AddService(typeof(IGraphicsDeviceManager), graphics);. Потім при отриманні послуги ви можете вказати інтерфейс як тип і передати його обраному підкласу.
Джон Поллик

@JohnPollick, для першого питання. Я намагаюся завжди просити його (тому що це могло змінитися), але якщо мені справді потрібно щось, кожен кадр я створюю змінну члена. У мене немає великої статистики ефективності, окрім того, що це ніколи не було вузьким місцем для мене. По-друге, так, це добре виглядає :). І на третій. Це дійсно причина аргументу типу, однак ніколи не слід звикати занижувати отримані значення, оскільки це руйнує вашу здатність міняти класи як сервіс. Якщо ви не хочете IGraphicsDeviceManger, а MyGDM, можливо, створіть новий інтерфейс.
Рой Т.

1
Ой, я не бачив, щоб тебе також закидали. Звичайно, це може зробити висновок про тип, якщо ти будеш робити перший :).
Рой Т.

5

То чому б просто не зробити ці екземпляри Singleton? Ну, тому що одиночні погані, оскільки вони мають глобальний стан, запобігають тестуванню та роблять ваш дизайн набагато крихкішим.

Як правило, одиночні беруть багато корисних рис і збирають їх разом у жахливий гібрид, який дає вам кілька речей, яких ви не хочете, а також той біт, який ви хотіли. (Чи були це характеристики "на замовлення"? Глобальна сфера застосування? Принаймні один екземпляр? Заборона декількох примірників?)

Локатори сервісів для багатьох однаково вважаються анти-зразком, оскільки замість того, щоб просто передавати залежність об'єкту, ви передаєте локатор сервісу (Гра), який з'єднує цей клас з рештою сервісів.

Ви не можете повністю уникнути з'єднання. Речі використовують інші речі, і без цього ваша програма нічого не робить. Тож єдине реальне питання - на якому рівні абстракції це.

Більшість текстів щодо орієнтації на об'єкти розрізняють склад і агрегацію. Важливо знати концептуальну різницю між тим, чим ти володієш, і тим, що ти знаєш. На жаль, більшість сучасних мов тут не мають чіткого розрізнення, і посилання на об'єкт може означати будь-яку з цих речей. (За іронією долі, C ++ робить кращу роботу, якщо ви використовуєте різні типи розумних покажчиків.)

Один з способів , в яких ви можете зробити композицію і агрегації ясно в вашому коді є використання послуг для агрегованих об'єктів. Послуги - це один із способів надання доступу до речей, якими ви не володієте, але якими ви можете користуватися.

Тож чому чомусь рекомендуються Послуги в розробці XNA та ігор?

Я не думаю, що вони загально рекомендуються в розробці ігор.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.