Let’s say I am tasked with coding some kind of an RPG. This means that, for example, I’ll want to track a CharacterGameCharacter and stats thereof, like intelligence, damage bonuses or hitpoints.
I’m positively scared that by the end of the project I may end up with handling with very a high number of fields – and for each I would have to make sure they follow a very similar set of constraint and behaviours (for example, I want them to be bounded between a min and a max; I want to be able to distinguish between a ‘base value’ and a ‘temporary bonus’; I want to be able to increment and decrement both without going through a setters and getters). Suddenly, for every field I would need one (two?) getter and four setters and maybe a couple resetters too! Even for 10 fields that means a LOT of methods all alike, eek.
For DRYness I have started encapsulating the logic of messing with those stats in Field classes, so that I could write code such as intelligence.applyBonus(10) or hitpoints.get() (which takes care the value returned is in range), etc. I have even gone to such a length to create classes to group those fields together, but that’s not the point right now.
Now, I hit in this problem while ‘plugging’ Field into GameCharacter: most Java textbooks say that each class should have private fields with public getters and setters. That sounds good in theory, and I’ve already built a whole class around an int; however, the idea doesn’t sound as solid when you find yourself calling a getter to get… a getter:
thisCharacter.getIntelligence().get() //eeek
I’d much rather access the field directly. Maybe it’s my Python/VB [1] ‘background’, but for me it is cleaner, clearer and more straightforward:
thisCharacter.intelligence.get()
The (theoretical) problem with public fields is that I’m giving up all control on it; for example at some other point in the codebase, by misfortune, the following might happen:
thisCharacter.intelligence = somethingThatReallyIsNull;
Sounds like a subtle bug… but… I mean, should I really worry about that? I for one never plan to assign the Field directly [2], I have documented in the Javadoc that this is not something that should be done, but still I am new here so I’m a bit torn.
So I would like to hear what your take on this topic. Are the advantages of encapsulation so massive that I should go ahead and have getter getters and setter getters and so on… or should I take encapsulation in healthy measures and leave the Field as a public field?
[1] Yes, I know. I’ve been trying to forget. But we’ve just recently seen also a bit of C# and man, aren’t properties sweet. Oh well.
[2] except in Constructors! And a getter won’t save me from a faulty constructor.
My experience is that in situations where you need a lot of fields, the number, nature, naming, and types of fields are so flexible and likely to change throughout the lifetime of your project that you would likely need some sort of map instead of fields.
For example have an attribute map from keys to values.
Provide public calls for getting and setting the attributes, but don’t let everybody use them (or make sure they don’t). Instead, create classes to represent each attribute you are interested in, and that class provides all the functions for manipulating that attribute. For example, if you have Strength, you could have a ‘StrengthManipulation’ class that is initialized to a specific Player object, and then provides getters, setters (All with appropriate validation and exceptions), and perhaps things like calculating strength with bonuses, etc.
One advantage of this is that you decouple the use of your attributes from your player class. So if you now add an Intelligence attribute, you don’t have to deal and recompile everything that manipulates only strength.
As for accessing fields directly, it’s a bad idea. When you access a field in VB (at least in old VBs), you usually call a property getter and setter and VB simply hides the () call for you. My view is that you have to adapt to the conventions of the language that you are using. In C, C++, Java and the like you have fields and you have methods. Calling a method should always have the () to make it clear that it is a call and other things may happen (e.g., you could get an exception). Either way, one of the benefits of Java is its more precise syntax and style.
VB to Java or C++ is like Texting to graduate school scientific writing.
BTW: Some usability research shows that it’s better to not have parameters to constructors and rather construct and call all the setters if you need them.