Alternative to global classes?

Started by
14 comments, last by Nairou 16 years, 1 month ago
Quote:Original post by Nairou
Quote:Original post by stonemetal
Maybe you should split your settings up. after all why does the renderer need the physics settings or ai settings?


Very true, but what is the alternative? Having every class open it's own settings? Depending on how settings are stored, that might mean reprocessing the same file multiple times or maintaining multiple copies of settings in memory.


The details of how settings are kept in persistent storage shouldn't be the concern of the sub systems, that concern should belong to a SettingsParser which accepts a stream and reads in the system settings.

It might work like this:
// Settings are distributed into appropriate classes and// instances of these classes are what get returned by the SettingsParser.class LoggerSettings;class VideoSettings;class PhysicsSettings;// ...// Some higher level system constructorvoid Engine::Engine(){    // Load in settings    std::ifstream settingsFile( SETTINGS_PATH );    SettingsParser settings( settingsFile );    // Initialise sub-systems    this->logger = new Logger( settings.getLoggerSettings() );    this->renderer = new Renderer( settings.getVideoSettings(), this->logger );    this->physicsController = new PhysicsController( settings.getPhysicsSettings(), this->logger );    // ...}
Advertisement
You should havea more tree like class structure. If too many class pointers are being passed into your renderer then group some of them appropriately. It's all about abstraction (OO-design). You really shouldn't need any global variables. I probably shouldnt say this but if you really absolutely insist on globals then I'd at least use singletons not global functions (but don't do it there are only very rare cases where this is ok).
Another reason why you should not be using globals nor singletons is unit tests! If you want to properly unit test your class, you will need to mock out correctly your logger, settings, etc.

In that regards, functional programming (and referential transparency) has been a real eye opener to me. I think there is nothing wrong in having constructors that take (shared) pointers to various dependent objects. On the contrary, it makes the dependencies much more visible, and that is a winner in the long term.

If the list of objects to be passed becomes too big, you have several solutions:

- If the list is mostly the same all the time, have an object "context" that contains pointers to your subsystems, and pass "context" around
- If the list is really big, or changes dynamically, pass a map of subsystems, and with a bit of template magic / dynamic type, get back your subsystem when you need it.

A little more code for a nice and clean code base cannot be under estimated.

void SomeClass::SomeFunction(...){    Logger log("logfile.txt");    if (worked)         log << "It worked!";}


Honestly logging should be simple and basic. You should also have some way of disabling it for speed also.

A lot of people didn't mention internal messaging systems. Then you just pass around this one class to all the others that want to communicate and presto, 99% of your issues solved. You can start off with a very basic one and build into more complex systems.

It seems to be the one topic most people avoid, and when its rarely discussed its at a high level or too complex for most new people to comprehend.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

I make a CGame class that has all the stuff my game needs to run. Anything that would be a global just ends up being a member variable of the game class. I create an instance of it in my main function, and everything that the game needs is inside, and is taken care of by a simple CGame->Update() call.

Of course, all the little things are still seperated into their own classes. They are all just strung together through CGame.
Thanks for all of the excellent suggestions! I think what I'm going to end up doing is like what small_duck and Mike2343 suggest. I've started changing some of the smaller classes (like the logger and the settings) to have static data so that they can be created on the fly when needed without losing everything. And I may create a small structure of the most common class pointers to pass to the constructors of other classes, though this may not end up being necessary now that I'm making the first change.

This topic is closed to new replies.

Advertisement