In Java, is there a design pattern or trick that can handle the "I want static methods declared in interfaces so that my classes are forced to implement them?" I've read a lot about static classes in interfaces lately, but nothing that can satisfy this particular issue.
Example: Suppose I'm making a game, let's call it StarClone. I have a save file that lists the last known location of soldiers and beasties. Suppose one of those beasties is a unit called a Zerkling. My game AI is interested to know how many Zerklings exist in its forces, because if this number passes a certain threshold it will perform a "Zerk rush" attack at the player's base. For this example, the value is stored as a static integer which is a member of the Zerkling class.
Now, I would really love to enforce the fact that each unit's class has a method, countsHowMany, which takes this save file and sees how many of that particular unit exists--at least that's what it could do, but each class will implement this however it wants. Since the member variable is static, it seems sensible that the method that sets it is also static. I may not have an instance of a Zerkling upon which I may invoke a non-static countsHowMany method, as a count of 0 is possible. We could argue that the variable is probably initialized to 0 to start with, but think of cases where the initial value is not usable in the same way; e.g. in my actual project, I'm retrieving game sprite images; these start out as null.
It seems like a desirably efficient design to simply have a list of all of my soldier and beast classes in one spot, grouped into a collection by an interface which we can call ICountMyself. So we can do something like:
for ( Class <? extends ICountMyself> currentClass : listOfUnitClasses )
{
currentClass.countHowMany( savedGameFile );
}
But of course, static methods in interfaces don't currently work like this in Java.
One possibility that might work around this is to have the method countsHowMany be non-static. Then, I when I am iterating through the classes, I can create a new instance of the class, invoke its respective countsHowMany method, and the non-static method would in turn modify the static member variable. This seems a little wasteful; imagine if I had to modify a cookbook in this fashion to use a different amount of salt for its recipes. I would be forced to flip through each page, find every entry of salt, cook the dish, scratch out the quantity and write in a new one, and finally throw the uneaten food into the garbage.
Any other way I can tackle this issue?
Thanks in advance!
Edit: Thanks to all for your swift and insightful answers! I am reminded of the fact that a valid answer to any question in computer science is "Well, it depends…" I originally did not wish to be so specific that my question lost its general applicability, but please allow me to elaborate somewhat on the original problem.
As I mentioned briefly, the original issue dealt with image sprites being loaded. The images are pre-loaded (for performance reasons) by an Image Manager package that I've put into a jar, hoping to have something general enough to re-use between games.
In trying to adhere to a more object-oriented approach, the game logic delegates responsibility for drawing units to the objects themselves. The base unit class takes care of implementing the drawsToScreen interface methods. In turn the base unit class calls an abstract method, getSprite(), which is implemented by the concrete classes. I trust each object to know its own state, thus it can determine which sprite frame to return from this call.
All that's left is getting the correct image references from the Image Manager, which is why I was curious about how to use static methods to set static member variables in this way. This saves me the trouble of hunting through a hash table of images every time I want to find the one I want. Ideally, a Zerkling would know what images to use to draw itself to the screen before I've even instantiated one.
Zerkling.countHowMany(),OtherUnit.countHowMany(),YetSomethingElse.countHowMany(), explicitly in your code. Or did you have any other thought for how you plan to do this?