Untangling Java classes, or Not
Saturday, 30th May 2015
Since I'm at the stage where I can start thinking about developing an actual game, I decided to tidy up my decade-old board game applet code for inclusion in an Android project. This code was my first major object-oriented project, and works quite well (or it did, till Oracle's security clampdown prevented most people from running it at all).
Tidying it up involves a number of things. Some classes' names could have been better chosen, so those could be changed. The Board class was restricted to rectangular grids, so I'd change that to an abstract 1-dimensional board from which subclasses could create rectangular, circular and any other shape of board. It was also restricted to one piece per playing space, so I added stacking. And the change that caused me a bit of a headache now and ten years ago, splitting the classes into separate source files like good Java programmers should always do.
This came with a snag. The classes are interdependent. The object which dispenses wisdom about rules and what moves are valid, for instance, needs to know about board positions and other game state information. But the game state object needs to know what game it is playing, i.e. the rules. Lots of other relationships like this exist between the board, the game, the moves, the rules and the player. This is why, as a budding Java programmer eleven years ago, I bundled these two classes and the others into a single source file. As soon as I put them into different source files, the rules class wouldn't compile without the game state class having been compiled first, and vice versa.
One school of thought says that my applet is therefore badly designed. Classes should follow a kind of hierarchy where this interdependency has no place. If class A needs class B, class B should not be similarly reliant on class A. I read lots of this when looking for a solution. So I set out to untangle these circular dependencies while still retaining an accurate model of all the aspects of a board game.
Unfortunately this ended up with one class at the top of the hierarchy doing almost all the work. I'd like to address a game state object and tell it that a move is being made, and allow the game state object to modify itself accordingly, consulting the rules object to check for side effects (the simplest being to update whose turn it is). But since the rules object became the top of the hierarchy, the game state couldn't consult the rule book and so the method had to be moved into the rules class. That's counter-intuitive as well as ugly.
I asked for advice on the excellent Programmer's Stack Exchange site and received a range of answers, from those I'm not yet equipped to understand properly to those that were very straightforward. The easiest of the lot told me that there's nothing inherently wrong with interdependent classes like my decade-old examples, and that I can simply compile the lot at once with a command like "javac *.java".
So I've left the class structure much as it is, and contented myself with improving its naming and implementing the board layout features that I mentioned before. This means that a lot of the specific game rule classes that I wrote all those years ago can be plugged almost unchanged into a range of Android apps. That's good news, as it means that I won't have to deal with game logic again; I can concentrate on implementing these games with an Android interface. I'm sure that that will bring me problems enough!