Consider the difference between Listing 6-1 and Listing 6-2. Both represent the data of a
point on the Cartesian plane. And yet one exposes its implementation and the other completely
hides it.
The beautiful thing about Listing 6-2 is that there is no way you can tell whether the
implementation is in rectangular or polar coordinates. It might be neither! And yet the
interface still unmistakably represents a data structure.
But it represents more than just a data structure. The methods enforce an access
policy. You can read the individual coordinates independently, but you must set the coordinates
together as an atomic operation.
Listing 6-1, on the other hand, is very clearly implemented in rectangular coordinates,
and it forces us to manipulate those coordinates independently. This exposes implementation.
Indeed, it would expose implementation even if the variables were private and we
were using single variable getters and setters.
Hiding implementation is not just a matter of putting a layer of functions between
the variables. Hiding implementation is about abstractions! A class does not simply
push its variables out through getters and setters. Rather it exposes abstract interfaces
that allow its users to manipulate the essence of the data, without having to know its
implementation.
Consider Listing 6-3 and Listing 6-4. The first uses concrete terms to communicate
the fuel level of a vehicle, whereas the second does so with the abstraction of percentage.
In the concrete case you can be pretty sure that these are just accessors of variables. In the
abstract case you have no clue at all about the form of the data.
In both of the above cases the second option is preferable. We do not want to expose
the details of our data. Rather we want to express our data in abstract terms. This is not
merely accomplished by using interfaces and/or getters and setters. Serious thought needs
to be put into the best way to represent the data that an object contains. The worst option is
to blithely add getters and setters.