When creating Java objects that will be referenced frequently at multiple levels, is it better to use class instances or make classes static?
I'm writing a java game. I need a master database of the unit prototype Database is just a class containing HashMap, which stores dozens of class instances containing statistical information of single cell type When the game generates a new unit, it will copy the unit out of the database and find it in the HashMap using the unit name When the program starts, the database will be built once and will not change Nor do I extend or modify any classes stored in HashMap It means a read - only reference for the game system
I have several other categories, basically the army, including many units When an army acquires a unit, it copies the unit's information from the database I have three methods to provide a method to read the main database for the military class I think your opinion is what is the best solution to create a simple, readable code without strange errors
I've included some simple code to illustrate different methods (sorry, if I miss semicolons or other things, I put my examples together quickly, and I'm still learning Java)
Method 1) I create the database as a class instance. Every time I create a new army or call the army method to add a unit to the army, I pass the army or method as a parameter to the database instance It should be easy to imagine
Method 2) I create the database as a class instance In the military class, I have a static reference database instance, which is set once by the static method in the military class After populating the database with data, the static method is called and the static reference is set to point to the database After that, the army can always extract information from the database by referencing static variables
class database { // HashMap of unit archetypes private HashMap<String,Unit> unitLibrary = new HashMap<String,Unit>(); // method for storing units in HashMap void storeUnits(String fileName) { // load unit stats from file // add new Unit instances to unitLibrary } // getter method Unit getUnit(String unitName) { return unitLibrary.get(unitName); } } class Army { // variables private static Database masterDatabase; private static boolean databaseSet = false; ArrayList<Unit> armyUnits = new ArrayList<Unit>(); // method for creating static database reference void setReference(Database d) { // set static reference to main database if not prevIoUsly set if (!databaseSet) { masterDatabase = d; databaseSet = true; } } // add unit to army void addUnit(String unitName) { armyUnits.add(masterDatabase.getUnit(unitName); } } public class CodeTest { public static void main(String[] args) { // create master database Database masterDatabase = new Database(); masterDatabase.storeUnits("FileOfUnits.game"); // set static reference in army class to point to master database Army.setReference(masterDatabase); // Create army Army army1 = new Army(); army1.addUnit("Soldier"); } }
Method 3) I create HashMap as static in the database class and fill it with data using static methods The getter method in the database class is also static At present, there is no reference passed at all, because every time the military class instance needs to be extracted from the database, it only runs database getUnit().
class database { // HashMap of unit archetypes private static HashMap<String,Unit>(); // method for storing units in HashMap static void storeUnits(String fileName) { // load unit stats from file // add new Unit instances to unitLibrary } // getter method static Unit getUnit(String unitName) { return unitLibrary.get(unitName); } } class Army { ArrayList<Unit> armyUnits = new ArrayList<Unit>(); // add unit to army void addUnit(String unitName) { armyUnits.add(Database.getUnit(unitName); } } public class CodeTest { public static void main(String[] args) { // prepare master database Database.storeUnits(); // create army Army army2 = new army2(); army2.add("Soldier"); } }
I've tried all three methods, and they all work, but the code is still in its infancy. Because of my early architecture, I don't want to encounter thorny errors I know it is not encapsulated in the traditional object-oriented way, but method 3 actually seems to me to be the cleanest, because the database is created in the background and will never be accessed through a bunch of different methods The code also has fewer lines and no tricks like method 2
Do you have such suggestions or experience? I've done a lot with Python, but I've only recently started learning Java and still try to get used to encapsulation restrictions
Solution
Method 1 is the best
This seems to me to be the crux of the problem You try to solve dependency injection with static variables, which is a bad idea If you think this is a problem, a framework like spring can save you the trouble of passing objects using functions such as autowiring
What if, in your second example, I created an army and forgot to set up the database? I have a valid object in a semi - created state Objects should never be in this state If you need to pass it to the constructor, you can avoid this potential bug
Your second and third examples have maintenance problems because they limit you to a single instance when you don't know how your requirements may change How do you know that two different armies will always share a database? What if you want a modern US Army and an ancientmacedonian army in the future? Did you know they would share the same prototype?