Style/Structuring question: One vs. multiple global objects

Henning Hasemann hhasemann at web.de
Mon Jul 2 09:13:32 PDT 2007


> Like:
> 
> struct GodObject {
> 	MainCharacter dude;
> 
> 	void gameLoop() {
> 		engine.actOnInput(dude.getInput());
> 	}
> }

Oh, I see we talked about the same thing with different words.
The situation is/was roughly like this:

import character;

class Game {
  Character mainCharacter;
  void gameLoop() {
    // ...
  }
}

The point is: When something imports game.d, that in turn will import
character which may itself be tempted to import game etc, so here is no
further division possible without either splitting the god 
object "Game" into multiple globals or use the "Dependency inversion"
pattern I found yesterday on the page torhu pointed me to
(http://www.shfls.org/w/d/dimple/).

This pattern seems very useful (I even think it woll solve almost all
of my module-structuring problems), but I hesitate to build a structure
like this:

thing.d:
--------
class Thing {
  // some functionality, that is also needed by character
}

icharacter.d
-------------
interface ICharacter {
  // ...
}

character.d:
------------
import thing;
import icharacter;
class Character : Thing, ICharacter {
  // ...
}

game.d:
-------
import icharacter;
class Game {
  ICharacter mainCharacter;
}


In this case I think I will prefer making mainCharacter a simple global
variable that can be found in character.d or whatever since the
dependency inversion approach (which I love in general) here has a few
disadvantages:
* unneccessary complicated when it comes to express the relation between
  character and thing
* probably misleading to other coders (ICharacter vs. Character)
* there seem to be only few argument relly against a hand full of
  globals

> See above. Pass around the current main character if you have a
> "struct/class Game", or define it as a global in maincharacter.d if
> you're willing to use globals.

atm I tend to the latter
 
> This is why I'd put such definitions in the modules their types are
> defined in, in this case. Generally, it's the kind of types that
> don't need to import anything else from the project are the ones
> that'd end up in a globals.d.

Ah okay then your glabals.d scheme can work ;-)

> 
> Not a problem. If you can think of something, feel free to enlighten
> me, too. I'd really like a general-purpose solution which doesn't
> involve all the kinds of hacks we have to resort to now.

Well the dependency-inversion thingy I found
(http://www.objectmentor.com/resources/articles/dip.pdf) was really
enlightning, maybe it helps you too.
The basic idea is to misuse interfaces to simulate some of the benefits
of C++'s header files.

Small example (dont take the methods too serious ;-))

scene.d:
import thing;
class Scene { Thing myThing; }
Scene currentScene;

thing.d:
import viewport;
class Thing { void draw() { /* do sth. for ex. with viewport.width */ }}

viewport.d:
import scene;
class Viewport {
  void eachFrame() {
    currentScene.draw();
  }
}

This is a nice cycle, which can easily be broken by abstracting scene
with an interface (which also yields the possibility to handle movie
sequences similar to interactive scenes with a common interface):

new scene.d:
import thing;
import iscene;
class Scene : IScene {
  // same stuff as before
}
class Movie : IScene {
}


iscene.d:
// does not need to import thing
interface IScene {
}


Note that this pattern doesnt seem to work if Scene looks like this:

class Scene : IScene {
  Thing getThing(); // everyone uses this method
}

because then IScene imports thing as well as Scene did so the cycle is
not broken here (if you iteratively spread this pattern over all your
classes including Thing it should work but then you have lots of
unneccessary interfaces and your code would become pretty unreadable).

HTH
Henning

-- 
GPG Public Key:
http://keyserver.ganneff.de:11371/pks/lookup?op=get&search=0xDDD6D36D41911851
Fingerprint: 344F 4072 F038 BB9E B35D  E6AB DDD6 D36D 4191 1851


More information about the Digitalmars-d-learn mailing list