3

Example:

You have a game with different schools of magic (fire, ice, etc). Each school has a set of properties that pertain to independent features of the game, such as:

  • strings to be displayed on the GUI (generic data stored in memory)
  • graphics, sounds, and other files to be loaded as necessary
  • different behaviours (code), e.g. each school of magic has a different interaction with various terrain types

I can think of two designs for implementing this, but I don't particularly like either of them.

  1. I could make an abstract MagicSchool class that contains all the various properties of a given school. This makes the MagicSchool class dependent on many distinct features of the game (GUI, SFX, other areas of game logic etc), which seems like an unnecessary mixing of concerns (something of a god class).
  2. I could put the GUI/SFX/etc data for each school in the GUI/SFX/etc systems as arrays. But then the code for the magic schools gets scattered all across the project (albeit in very logical places).

So in this case, there are two axes along which to structure code: the various magic schools, and the various features in which the schools feature.

In terms of clarity and maintainability, which of the above two solutions should I prefer? Or perhaps there's another way I haven't considered yet?

  • I have a very similar problem. Our product is a data acquisition system with lots of different sensors. There is a hardware layer, a GUI layer, a calibration layer... Each time I have to add a sensor to the codebase, I have to spray a bit of code in every layer... Very un-natural and error prone... – heltonbiker Dec 12 '13 at 1:22
  • Isn't the school just a key then? Each actual component can see the key (oh I need to use the Fire UI) and switch on that (hopefully to some plug-in that you ship as a bundle with all of the other school parts). The components still own their stuff rather than the school. – Telastyn Dec 12 '13 at 1:36
  • The first two bullets seem trivial: The class can return whichever is appropriate for that magic school. The third bullet is the interesting one. – Izkata Dec 12 '13 at 1:38
1

I'm not sure I fully understand the problem, let's say what if we do it this way (in a Java-like language):

Define interface's for your three bullets, say GUI, FX and Behavior. For example:

interface GUI {
    String name();
    ....
}

interface FX {
    Image image();
    Sound sound();
    ....
}

interface Behavior {
    Interaction interact(Terrain t);
    ....
}

Each abstract MagicSchool is a product of objects drawn from each of the above interface:

abstract class MagicSchool(GUI gui, FX fx, Behavior b) {
    GUI gui();
    FX fx();
    Behavior behavior();
}

To display a school's GUI element, we can do something like:

System.display(school.gui().name());

Now for example, you want to define Fire:

class FireGUI implements GUI { .... }
class FireFX implements FX { .... }
class FireBehavior implements Behavior { .... }

Now you define FireSchool as the product of these, overloading the constructor:

class FireSchool = MagicSchool {
    FireSchool() {
        super(new FireGUI(), new FireFX(), new FireBehavior());
    }
}

Or if you don't actually need a new class, just define ad-hoc schools and behavior:

iceSchool = new MagicSchool(new GUI() { /* Ice GUI */ },
                            new FX() { /* Ice FX */ },
                            new Behavior() { /* Ice behavior */ });

Java doesn't have a convenient way of doing higher-order functions, so I promote GUI, FX, Behavior to the level of interface to reduce syntactic burden at a few places. If your language has first-class functions, just define all those as objects.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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