In my last Java programming video I talked about making everything private to start when
designing classes, especially attributes. It's a contentious point lately. I've seen
a few articles against this circling the internet, and I've been asked about it. Seems like a
good topic to dive deeper into.
In this video I want to dive more into why private scope should be your default starting
point when designing classes. We'll talk about what it means in general for methods, and
then we'll talk about the contentious point, getters and setters.
If we start out with everything private, there isn't much you can do with the class. There's
little you can do to mess it up too. Once you expose a method or attribute publicly,
you've provided one new way another class can change your class.
This leads to something called the "principle of least privilege". It's usually applied
to security, but it also works with encapsulation. The idea is we want to expose an API for another
class to perform the task it needs to, and nothing more. A simpler API means it's easier
to understand, it manages complexity in our application, and it's much easier to test.
In this example, the only API exposed to other classes is moveSpaceship(). The checks and
action are all internal workings of the class. Other classes do not need to know how it happens,
they just need to tell the spaceship to move.
Starting with everything private makes a much smaller exposed API for our class which is
easier to understand. There's nothing to call. Add one call another class can make, and it's
very easy to understand how to use our class. We make that one call. That's important because
other classes do not need to know how our class works, they just need to know how to
use it. Fewer public calls make it easier to understand.
A simple API helps manage complexity. Imagine we have a class that is called from other
classes. If we have one public method, that's one way each class can interact with our class.
That's pretty simple to understand. Now imagine there's 100 ways to our class. That makes
a very complex system, and it's not easy to see how things work.
We want to manage complexity because it makes our system easier to test. Each line in the
diagram is one interaction that requires testing. Everything private can be tested in a unit
test. Failures between classes can only happen where classes can touch.
So let's talk about getters and setters. They are not popular, because it looks alot like
boiler plate code. It's simpler to make the attribute public. Why is that bad?
Well a public attribute makes the value and the behavior of changing the value the same
thing. That violates encapsulation. We cannot apply any rules for how the values are modified.
The value gets modified, and there is nothing we can do about it. Our object can be placed
in an invalid state.
Using getters and setters allows us to separate the behavior of changing the value, and the
value. We can make our setter private, and now we have a read only value. Or we can use
our setter to perform validation or other operations on the value before modifying the
class state. If our rock can only be at positive positions, we can make sure the value is greater
than zero before setting it.
A getter allows us to separate when a class state is returned. For example if it takes
a long time to calculate the attribute, we can lazily load the attribute. Calculate the
value when we need it. From the calling class, we just get the value. In this calse, what
occurs in the process of getting X is hidden. The calling class doesn't need to know about
calculating X.
And it means our our API only has one meaning for the getter. Get the value. That's a simple
API, and the ability to set the value isn't exposed at the same time like it is with a
public attribute.
So your next thought is probably, let's make our attribute immutable. That means the attribute
is marked final. If our immutable reference points to a mutable class, exposing it directly
means anyone can change the values. They just can't change the reference to a new class.
At that point, we might as well make the attribute mutable, because immutability isn't helping
us.
Making the attribute immutable helps for primitive attributes, but we're still locked to our
API. We can't make internal changes to our class, without changing the API. If we later
need to perform validation on attributeOne, we have to change how it’s set and retrieved.
That means any change to a public attribute will have downstream affects on every class
that uses our class.
What about package scoped classes? That's probably the only place we could even consider
making attributes public. The package scope of the class will limit what classes can change
attributes, and if we need to change the API the number of downstream classes affected
will be few. The only thing we'll gain is more succinct code, but that's a plus and
the downside of a changed API is manageable.
It's all about controlling how our class is used, and more importantly how it's state
is changed. Public attributes allow type safety, and that's it. There's no other protection.
So hopefully we're on the same page about public vs private attributes. If not, let
me know in the comments below.
Hey! Thanks for watching the video. If you like what you're seeing or have any questions,
let me know in the comments or on DeegeU.com! New videos come out each week, so make sure
you subscribe. You don't want to miss a video! In fact, lets go watch another DeegeU video.
See you there!