Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

The Microsoft.Xna.Framework.Game class has a Services property that allows the programmer to add a service to their game by providing the type of the class and an instance of the class to the Add method.

Now, instead of having to pass an AudioComponent to all classes and methods that require it, instead you just pass your Game instance and look up the service. (Service Locator)

Now, because games have many services (GraphicsDevice, SceneGraph, AudioComponent, EffectsManager, et cetera), you will now basically be passing Game to everything.

So why not just make these instances a Singleton? Well, because Singletons are bad because they have a global state, prevent testing, and make your design much more brittle. Service locators are equally considered to be an anti-pattern to many because instead of just passing the dependency to an object, you pass a service locator (the Game) which couples that class with the rest of the services.

So then why are Services recommended in XNA and game development? Is it because games are different from regular programs and are highly intertwined with their components and having to pass every component necessary for the functioning of a class would be highly cumbersome? Are Game Services just then a necessary evil in game design? Are there alternatives that don't involve lengthy parameter lists and coupling?

share|improve this question
3  
"Service locators are equally considered to be an anti-pattern to many" - [citation needed]. Obviously using them where you don't need them is bad - true of all software constructs - but I've never heard service locators called an anti-pattern. (On the other hand, I also try to avoid programmers that spend most of their time discussing the latest pattern minutiae.) –  user744 Oct 19 '11 at 19:41
    
@JoeWreschnig although I do agree with you I did some digging and found this: blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx –  Roy T. Oct 19 '11 at 19:48
2  
Yes, but that guy is selling a book about using DI; obviously he doesn't want you using something simple, then you won't buy his book! (In all seriousness, Fowler's original DI/SL article covered this exact topic - martinfowler.com/articles/… - and that guy's blog rant adds nothing to the discussion.) –  user744 Oct 19 '11 at 19:55
    
I wish I could mark that link you just posted from Martin Fowler as answer (although it's not my question) –  Roy T. Oct 19 '11 at 20:07
add comment

2 Answers

up vote 6 down vote accepted

I don't think everyone agrees that service locators are bad. Service Locators provide a way to decouple important functionality that everyone needs from their actual implementation. Service locators also provide a way to swap services at run time. Also I don't think it's true that you need to pass around the service locator around everywhere. I think you can access it from everywhere. While a game class with globals would need to be passed around a thousand times per frame (which would cause bad performance).

To make the difference between the service locator and an class with globals a bit more clear consider the following example:

I'm making a game and use a gameA class object that has a global variable: the content loader. Now in my next game I don't want to use the gameA class but create a new gameB class. I now have to again add the globals of gameA to gameB which is extra work. Also it becomes hard to configure the type of content loader I want. Say I have a game that runs both on the PC and on the XBOX. On the PC I want a content loader that can also open a 'open file' dialog. While on the XBOX I definately don't want this. By having a config file I can even halfway trough the game easily change the content loader, even from somewhere else than the gameA class, without just making the globals in gameA all public.

Now consider I'm using a service locator. I can always keep using it. And even what kind of services are there can be different all the time. It is also true that I won't even care about their implementation as long as they have a common interface. (Although I could use that in a gamA like class aswell).

Anyway I think you will find the game services pretty handy. Everyone I know uses it. To help you out a bit more. I've created a small helper class around game services so that you can do quite a bit less casting all the time: http://roy-t.nl/index.php/2010/08/25/xna-accessing-contentmanager-and-graphicsdevice-anywhere-anytime-the-gameservicecontainer/ I use it quite a lot.

share|improve this answer
    
Thanks for the reply. In a class that would require a service, do you typically just request the GameServices class for the service whenever needed, or do you create a member variable in the class and request for the service only in the constructor? I suppose what I am asking is how slow return (T)Instance.GetService(typeof(T)); is. –  John Pollick Oct 19 '11 at 21:09
    
Also, what do you think of this implementation of the GameServices class? I removed the unnecessary singleton because it didn't have any features that the abstraction didn't already have. Also, I removed the redundant Service suffix at the end of every method. –  John Pollick Oct 19 '11 at 21:40
    
Also, I think the reason that the Services AddService method takes a type is so that you can specify the interface of the service. For example, Services.AddService(typeof(IGraphicsDeviceManager), graphics);. Then when retrieving the service you can specify the interface as the type and cast it to your chosen subclass. –  John Pollick Oct 19 '11 at 21:59
    
@JohnPollick, for the first question. I try to always request it (because it could've changed) but if I really need something every frame I create a member variable. I don't have much performance statistics other than that it's never been a bottleneck for me. The second, yeah it looks fine :). And for the third. That is indeed the reason for type argument, however you should never make a habit of downcasting retrieved values because that destroys your ability to swap classes as service. If you don't want an IGraphicsDeviceManger but a MyGDM then possibly create a new interface. –  Roy T. Oct 20 '11 at 6:26
1  
Oh I didn't see you also casted. Of course it's able to infer the type if you cast first :). –  Roy T. Oct 20 '11 at 14:26
show 3 more comments

So why not just make these instances a Singleton? Well, because Singletons are bad because they have a global state, prevent testing, and make your design much more brittle.

Singletons generally take a lot of useful traits and package them together in an awful hybrid that gives you several things you don't want along with whichever bit you did want. (Was it 'create-on-demand' characteristics? Global scope? Enforcement of at least one instance? Prohibition of multiple instances?)

Service locators are equally considered to be an anti-pattern to many because instead of just passing the dependency to an object, you pass a service locator (the Game) which couples that class with the rest of the services.

You can't avoid coupling entirely. Things use other things and without that your program does nothing. So the only real question is what level of abstraction it's at.

Most texts on object orientation make a distinction between Composition and Aggregation. It's important to know the conceptual difference between something that you own and something that you know about. Unfortunately most modern languages don't have a clear distinction here, and a reference to an object could mean either of these things. (Ironically, C++ does a better job, if you use the various smart pointer types.)

One way in which you can make composition and aggregation clear in your code is by using services for aggregated objects. Services are one way to provide access to stuff you don't own, but which you can use.

So then why are Services recommended in XNA and game development?

I don't think they are universally recommended in game development.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.