As a student in programming, I learned that encapsulation is one of the most important principles of object-oriented programming.
However, I only follow that principle when I feel like it suits my purpose. I sometimes leave internal class variables public if they are intended to be directly read at some time, and only use things like setters and getters when there are actual calculations (and assignments of other variables) involved in the assignment/evaluation of a variable (say, a getDegrees()
of an Angle
class that only stores radians internally).
If I find that some procedure done with a class involves a lot of modification of internal variables and is easily groupable into a single operation, I will put it into a function of the class rather than having the outside code call multiple smaller functions. However, I will not always enforce this in the interface by making the affected variables private instead.
Am I violating any principles by doing this? If so, how severely? The code that does this usually doesn’t face outward, as I pay a lot of attention to how out-of-program input is processed.
7
One of the advantages of using getters and setters (or properties) rather than public fields is that the logic can change without having to change the consumer. Right now you might only need to simply read and write to/from a variable, but what about in the future?
For example, in your Angle class, what would happen if you decided that from now on you want to store the angle as degrees rather than radians? You would now need a getRadians() method that does the appropriate calculation, and all the code that accessed Angle.radians directly would need to be changed to use this new method. On the other hand, your getDegrees() method could still be used. All that would need to change is its implementation.
If you’d used both getRadians() and getDegrees() methods to begin with, this internal change (from radians to degrees) would not concern the object’s consumers at all – its public contract stays the same.
One of the principles of encapsulation is that the internal representation of an object should not concern its consumers.
I’m working in a code base that sounds a lot like how you’re programming. It’s fairly awful. When you’re in college (as I was recently) these principles don’t make as much sense, because they’re simply asserted to you. All of your assignments are going to be very small compared to real-world applications, however, and they will rarely get a chance to become complex enough to the point where they become difficult to handle.
This notion is a worrisome:
I sometimes leave internal class variables public if they are intended to be directly modified at some time
When working on small projects, it sometimes seems more convenient to let your member variables be altered by outside classes. This is almost always a bad idea. The more internal variables you allow the external program to alter, the less well you can reason about the state of your class at any given point in the program.
This kind of design is indicative of a bad object model. If you’re finding that you have a class with variables that need to not only be read, but also written to frequently by other parts of the program, chances are those variables aren’t logically a part of that class.
In my experience, the best kind of class to work with is one that is almost, if not totally, immutable from the outside, and only allowed to make changes to itself internally. Even better if it never changes once it’s created.
Remember that not every variable needs a getter and setter. You should avoid writing either one entirely until you find out you absolutely must have them. Getters will almost always be more common than setters.
6
As I have learned more about OO Development, I’ve realized that an object with a lot of getters and setters isn’t really an object…it’s more of a struct.
People like to use real world examples to illustrate especially when talking to learners. So let’s use an example that everyone can understand.
When a person is conceived, he (or she) is giving certain parameters that will form his or her appearance. Height, weight, skin tone, eye color, jaw structure, etc., etc are all determined at conception via DNA. Consider conception as a person’s constructor, and the mother and father’s DNA as parameters to that constructor.
There are some properties about the person that can be set after construction (such as his name and birthdate — although, that is MOSTLY determined internally), but everything else can only be observed not changed (well except through surgery but you get my drift). Changes to a person’s height occur internally…no one says “Michael, grow two inches” my body determine how much I grow based on the inputs is give it (food, rest, whether or not I smoke, and of course my DNA).
Complex objects in an application should be like this model of a human. We provide some parameters at construction. We can perform operations on it (or even it performs operations on itself), and observe the results of our input and its interaction with the rest of the system. But its core data should be immutable to the outside.
Even simple objects that have data and little logic should be immutable because they represent values. For example look at a string in C# once you initialize it, you can’t change that copy of the string the same with Dates. Data sent between objects should be immutable or a copy of the original (C# supports this natively via Structs which are passed by value versus Classes which are held by reference).
1