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.
- I could make an abstract
MagicSchool
class that contains all the various properties of a given school. This makes theMagicSchool
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). - 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?
3
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.