Structure of classes in good Game Engine?

Started by
45 comments, last by Cygon 11 years, 9 months ago
I am not a huge fan of globals but when I am forced to use them, I usually do. The way I indicate if I should use them or not, is if they are used by the whole application and if they are dependencies. If they depend on a class, or a class depends on it, then I will not use it. A good example would be a logger. It does not require anything from other classes, it just holds a few functions and outputs information to a file/console. I most likely wouldn't even make it a class, it would just be a few static functions that I would call. At most, it would probably be two or three global variables.
There is a time where using globals too much can make it a pain to debug, but for a simple logger, it won't be too difficult to debug, especially when it's purpose is to help you debug :P
Advertisement

I found the service locator pattern (as described here http://gameprogrammi...ce-locator.html) a good alternative to the singleton. Its still very global but not that restrictive anymore.

Looks rather useful, and not just as a static variable.
Cygon mentioned it as a anti-pattern though..



  • Passing some semi-global application class around is just hugely increasing dependencies since now you don't know which objects a class will look up through the application class (the service locator anti-pattern).

Seriously, it's just for logging. Don't overengineer and overthink the solution. A thread-safe and simple function is generally sufficient. If you want to log to different outputs (file, network), use FILE structure or std::ostream.

MyLogger::log(std::ostream& stream, const std::string& what);

Done.
yes logging is one thing, but the discussion is also valid for other stuff..
For higher level objects or systems, dependency injection is always an option.

http://martinfowler.com/articles/injection.html

I found the service locator pattern (as described here http://gameprogrammi...ce-locator.html) a good alternative to the singleton. Its still very global but not that restrictive anymore.



Cygon mentioned it as a anti-pattern though..

[quote name='Cygon' timestamp='1340101692' post='4950531']

  • Passing some semi-global application class around is just hugely increasing dependencies since now you don't know which objects a class will look up through the application class (the service locator anti-pattern).


[/quote]

I had to laugh :)

Yep, it's widely considered an anti-pattern because the service locator is the equivalent of handing your classes a big box of other objects and letting them go shopping in it.

The dependencies are turned completely opaque since all you see from the outside is a constructor taking a [font=courier new,courier,monospace](ServiceLocator &)[/font] -- you have to rely on the documentation or consult the code to find out what dependencies a class really has. And those may change at any time. Missing dependencies (common scenario: component X adds a new dependency) result in an error at runtime if and when the code consuming the dependency is reached because the compiler can't determine if the service locator will have the required service when it is looked up. Such classes also become dependent on the service locator implementation (whereas dependency injection can happen without the knowledge of the partaking classes, see sauce for an example).
Professional C++ and .NET developer trying to break into indie game development.
Follow my progress: http://blog.nuclex-games.com/ or Twitter - Topics: Ogre3D, Blender, game architecture tips & code snippets.

This topic is closed to new replies.

Advertisement