Before finishing up the first version of my terminal view game, I moved strings like the welcome message and player prompts to a properties file. This requires reading and storing the strings before using them in the view, but has two big advantages. First, tests no longer break when I edit a string (at least, as long as my tests are using the same properties). Second, if I wanted to translate my program into another language, it’s as easy as swapping out the properties file.
Unfortunately, loading strings got ugly fast. Here’s an example from the GameController class:
It gets worse. When I started writing my Swing view, I needed to ignore certain strings, like those that prompt for keyboard input. A good idea: avoid creating a brand new SwingController class, but somehow filter out unneeded strings. A bad idea: do it by checking and ignoring certain strings from the controller. This is logic that really shouldn’t be in the view, implemented in a very fragile way. In fact, it undoes all the abstraction of the properties file—as soon as a string changes, displayMessage() will probably break. Plus, there’s plenty of duplicated code.
This is similar, though not identical to Fowler’s “Refused bequest,” where a subclass inherits lots of methods and then ignores them. Here’ I’m loading lots of strings, then ignoring them.
Refused bequest is fixed with a refactor called “Replace inheritance with delegation:” put the superclass in a field on the old subclass, remove the inheritance, and simply delegate to the superclass methods when needed. Here, I haven’t even shared code through inheritance, but by good old copy-and-paste (so it’s also part of the duplicated code stink parade).
The cleanup strategy here is similar too: create a separate class to handle loading properties, and use it in place of the duplicated methods. I’ll start by creating a StringLoader class that includes the duplicated fields and methods:
The repeated calls to viewStrings.getProperty() are still pretty ugly and very difficult to read. One solution is to extract a load() method, then iterate over an array of the property names:
This requires trading off a little clarity, but on balance it’s much cleaner. Best of all, now I can use properties as they were intended. Preventing my view from displaying certain strings just requires creating a new properties file and removing the content from the unneeded messages—another win for decoupling and abstraction.