Java Reference
In-Depth Information
6.6
Coupling
The fact that there are so many places where all exits are enumerated is symptomatic of poor
class design. When declaring the exit variables in the
Room
class, we need to list one variable
per exit; in the
setExits
method, there is one if statement per exit; in the
goRoom
method,
there is one if statement per exit; in the
printLocationInfo
method, there is one if statement
per exit; and so on. This design decision now creates work for us: when adding new exits, we
need to find all these places and add two new cases. Imagine the effect if we decided to use
directions such as northwest, southeast, etc.!
To improve the situation, we decide to use a
HashMap
to store the exits, rather than separate
variables. Doing this, we should be able to write code that can cope with any number of exits
and does not need so many modifications. The
HashMap
will contain a mapping from a named
direction (e.g.,
"north"
) to the room that lies in that direction (a
Room
object). Thus, each
entry has a
String
as the key and a
Room
object as the value.
This is a change in the way a room stores information internally about neighboring rooms.
Theoretically, this is a change that should affect only the
implementation
of the
Room
class (
how
the exit information is stored), not the
interface
(
what
the room stores).
Ideally, when only the implementation of a class changes, other classes should not be affected.
This would be a case of
loose
coupling.
In our example, this does not work. If we remove the exit variables in the
Room
class and
replace them with a
HashMap
, the
Game
class will not compile any more. It makes numerous
references to the room's exit variables, which all would cause errors.
We see that we have a case here of
tight
coupling. In order to clean this up, we will decouple
these classes before we introduce the
HashMap
.
6.6.1
Using encapsulation to reduce coupling
One of the main problems in this example is the use of public fields. The exit fields in the
Room
class have all been declared
public
. Clearly, the programmer of this class did not
follow the guidelines we have set out earlier in this topic (“Never make fields public!”). We
shall now see the result! The
Game
class in this example can make direct accesses to these
fields (and it makes extensive use of this fact). By making the fields public, the
Room
class
has exposed in its interface not only the fact that it has exits, but also exactly how the exit
information is stored. This breaks one of the fundamental principles of good class design:
encapsulation.
Concept:
Proper
encapsulation
in
classes reduces
coupling and thus
leads to a better
design.
The encapsulation guideline (hiding implementation information from view) suggests that only
information about
what
a class can do should be visible to the outside, not about
how
it does it.
This has a great advantage: if no other class knows how our information is stored, then we can
easily change how it is stored without breaking other classes.
We can enforce this separation of
what
and
how
by making the fields private and using an
accessor method to access them. The first stage of our modified
Room
class is shown in
Code 6.4.
Search WWH ::
Custom Search