Objects First With Java

Download Report

Transcript Objects First With Java

Designing Classes 2
How to write classes in a way that
they are easily understandable,
maintainable and reusable
Code Quality
Two important concepts for quality of code:
• Coupling – as little as possible please
• Cohesion – as much as possible please
Coupling
• Coupling refers to links between separate
units of a program.
• If two classes depend closely on many
details of each other, we say they are
tightly coupled.
• We aim for loose coupling.
Loose Coupling
• Loose coupling makes it possible to:
• understand how a class works without having
to understand how the classes it uses work;
• change the implementation of a class without
affecting those classes that use it.
This improves maintainability … makes change easier.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Cohesion
Cohesion relates to: the the number and
diversity of tasks for which a single unit is
responsible.
If a programming unit is responsible for one
logical task, we say it has high cohesion.
Cohesion applies both at the level of classes
and of methods.
We aim for high cohesion.
High Cohesion
• High cohesion makes it easier to:
• understand what a class or method does
(because it only does one thing);
• Choose and use descriptive names;
• reuse classes or methods.
This improves usability … and makes change easier.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Cohesion of Classes
Classes should represent just one,
and only one, well defined entity.
Cohesion of Methods
A method should be responsible for one,
and only one, well defined task.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Code Duplication
This is an indicator of bad design.
It makes maintenance harder.
It can lead to introduction of errors,
especially during maintenance.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
World of Zuul
Chapter 7: zuul-bad
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Chapter 7: zuul-bad
Problems
• Fields in Room are all public.
• The fact that a Room has four exits is
burnt into the interface of its setExits
method.
• The Game class references Room fields.
• So, the implementation of the Game and
Room classes are coupled. A change in
one (e.g. adding more exits to a Room)
means changing the other (e.g. the
createRooms, printWelcome and
goRoom methods of Game).
• This is BAD!
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Chapter 7: zuul-bad
Problems
• There are duplicated code fragments in
the Game class (in createRooms and
printWelcome methods).
• Changing the details of one of these
fragments means changing all.
• This is BAD!
• Factorise the duplicated code into a
single method (see Code 7.2, p209, of the
book: printLocationInfo) and
duplicate its invocation instead.
• Now, there is only one fragment of code
to maintain. This is Good!
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Chapter 7: zuul-bad

Chapter 7: zuul-better
• There are duplicated code fragments in
the Game class (in createRooms and
printWelcome methods).
• Changing the details of one of these
fragments means changing all.
• This is BAD!
• Factorise the duplicated code into a
single method (see Code 7.2, p209, of the
book: printLocationInfo) and
duplicate its invocation instead.
• Now, there is only one fragment of code
to maintain. This is Good!
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Chapter 7: zuul-bad

Chapter 7: zuul-better
• Make fields in Room private and provide an
accessor method to get them (Code 7.4, p213).
• In Game, can no longer reference directly the exit
fields (all Rooms) of Room.
• In Game.printLocationInfo (which does so
reference), we could just change it to use the
accessor method, rather than the field.
• However, it’s neater to invoke a (new) method of
Room to get the exit information it needs to print
(Code 7.6, p218). Each Room object has that
information, so it is really its responsibility.
• For Game.goRoom (which also does so reference),
thirteen lines of code collapse to one (see p214).
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Chapter 7: zuul-bad

Chapter 7: zuul-better
• Make fields in Room private and provide an
accessor method to get them (Code 7.4, p213).
• In
Game
, can no
reference
directly
Look
carefully
at longer
this accessor
method
… the exit
fields (all Rooms) of Room.
• In Game.printLocationInfo (which does so
reference), we could just change it to use the
accessor method, rather than the field.
• However, it’s neater to invoke a (new) method of
Room to get the exit information it needs to print
(Code 7.6, p218). Each Room object has that
information, so it is really its responsibility.
• For Game.goRoom (which also does so reference),
thirteen lines of code collapse to one (see p214).
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Chapter 7: zuul-bad

Chapter 7: zuul-better
public Room getExit (String direction)
{
if (direction.equals ("north")) {
return northExit;
}
if (direction.equals ("east")) {
return eastExit;
}
if (direction.equals ("south")) {
return southExit;
}
if (direction.equals ("west")) {
return westExit;
}
return null;
}
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Chapter 7: zuul-bad

Chapter 7: zuul-better
• Make fields in Room private and provide an
accessor method to get them (Code 7.4, p213).
• In
Gamea, String
can no longer
reference
exit
It maps
(direction)
intodirectly
an exit the
Room
.
(all Room
s) of
Room.of a:
• fields
But that’s
just the
function
• In Game.printLocationInfo
(which does so
HashMap<String, Room>
reference), we could just change it to use the
• So,
replace
the four
exit than
fieldsthe
with
one of the
accessor
method,
rather
field.
(private
of course)
– Code
7.5. Now,
we of
• above
However,
it’s neater
to invoke
a (new)
method
can
have
exitsinformation
as we like.it needs to print
Room
to as
getmany
the exit
• Finally,
replace
theEach
setExits
method
(Code 7.6,
p218).
Room object
has(which
that
information,
so it is“four
reallyexits”
its responsibility.
burns the message
into its definition)
a single
setExit
method
(which
we can
• with
For Game
.goRoom
(which
also does
so reference),
thirteen
of code
collapse
to one
(see p214).
invoke forlines
as many
exits
as we like)
– p216/217.
• Now, Room is independent of its number of exits.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
World of Zuul
MORAL: class
diagrams are
not enough to
tell whether the
design is good.
Chapter 7: zuul-bad
Chapter 7: zuul-better
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Responsibility-Driven Design
• Where should we add new fields and
new methods (and to which class)?
• The class that holds the data (fields)
processes (methods) the data.
• Responsibility-driven design leads to
low coupling.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Localising Change
• One aim of reducing coupling and
responsibility-driven design is to
localise change.
• When a change is needed, as few
classes as possible should be
affected.
Improve maintainability … make change easier.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Think Ahead
• When designing a class, think what
changes are likely to be made in the
future.
• Aim to make those changes easy.
Improve maintainability … make change easier.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Refactoring
• When classes are maintained, code
usually needs to be added.
• Lists of fields, lists of methods and
the code inside methods tend to
become longer.
• Every now and then, classes and
methods should be refactored to
maintain cohesion and low coupling.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Refactoring and Testing
• When maintaining code, separate
the refactoring from making other
changes.
e.g. zuul-bad to zuul-better.
• Do the refactoring first, without
adding to the functionality.
• Test before and after refactoring to
ensure that nothing gets broken.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Design Questions
• Common questions:
• How long should a class be?
• How long should a method be?
Answered with regard to cohesion and coupling.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Design Guidelines
• A method is too long if it does more
then one logical task.
• A class is too complex if it represents
more than one logical entity.
Note: these are guidelines …
everything is still open to the designer.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Review
• Programs are continuously changed.
• It is important to anticipate change
and make it as easy as possible.
• Quality of code requires much more
than just performing correctly!
• Code must be understandable and
maintainable.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
Review
• Good quality code avoids duplication,
displays high cohesion, low coupling.
• Coding style (commenting, naming, layout,
etc.) is also very important.
• There is a big difference in the amount of
work required to maintain poorly structured
and well structured code.
• In fact, unless it is well structured, the code
is doomed … it will not be used for long.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling