By default, all members are public. This means that the members can be accessed and modified from within an instance as well as from outside of it. Subtypes (classes that inherit from it; see Inheritance) will inherit public members. Public methods expose an API by which users may use your class. Public properties, however, should be less common in practice for a very important reason, which is explored throughout the remainder of this section.
Following common conventions in modern object-oriented languages, members
with an underscore prefix (e.g.
_foo) are implicitly private; this
behavior can be overridden by explicitly specifying an access modifier. This
convention allows for more concise member definitions and is more natural to
Encapsulation is the act of hiding information within a class or instance. Classes should be thought of black boxes; we want them to do their job, but we should not concern ourselves with how they do their job. Encapsulation takes a great deal of complexity out of an implementation and allows the developer to focus on accomplishing the task by focusing on the implementing in terms of the problem domain.
For example - consider a class named Dog which has a method
walk(). To walk a dog, we simply call
walk() method could be doing anything. In the case of a real dog,
perhaps it will send a message to the dog’s brain, perform the necessary
processing to determine how that command should be handled and communicate
the result to the limbs. The limbs will communicate back the information
they receive from their nerves, which will be processed by the brain to
determine when they hit the ground, thereby triggering additional actions
and the further movement of the other legs. This could be a terribly
complicated implementation if we had to worry about how all of this was
In addition to the actual walking algorithm, we have the state of each of the legs - their current position, their velocity, the state of each of the muscles, etc. This state pertains only to the operations performed by the dog. Exposing this state to everyone wouldn’t be terribly useful. Indeed, if this information was exposed, it would complicate the implementation. What if someone decided to alter this state in the middle of a walking operation? Or what if the developer implementing Dog relied on this state in order to determine when the leg reached a certain position, but later versions of Dog decided to alter the algorithm, thereby changing those properties?
By preventing these details from being exposed, we present the developer with a very simple interface11. Rather than the developer having to be concerned with moving each of the dog’s legs, all they have to do is understand that the dog is being walked.
When developing your classes, the following best practices should be kept in mind:
- When attempting to determine the best access modifier (see Access Modifiers) to use for a member, start with the least level of visibility
private) and work your way up if necessary.
- If your member is not private, be sure that you can justify your choice.
- If protected - why do subclasses need access to that data? Is there a better way to accomplish the same task without breaking encapsulation?
- If public - is this member necessary to use the class externally? In the case of a method - does it make sense to be part of a public API? If a property - why is that data not encapsulated? Should you consider an accessor method?
One would argue that this isn’t necessary a good thing. What if additional flexibility was needed? Dog, in the sense of this example, can be thought of as a Facade (GoF). One could provide more flexibility by composing Dog of, say, Leg instances, a Brain, etc. However, encapsulation still remains a factor. Each of those components would encapsulate their own data.