Object-Oriented Design Heuristics (1)

Download Report

Transcript Object-Oriented Design Heuristics (1)

TCSS 360, Spring 2005
Lecture Notes
Design Guidelines
Relevant Reading:
Object-Oriented Design Heuristics
Arthur Riel
1
OO design pyramid
Data structure & algorithm design for
attributes & operations (detailed design)
Class definitions, hierarchies,
generalizations (modules)
increasing detail
External and internal interfaces
(module coupling)
Supports hardware/software
system mapping (packages)
2
OO design pyramid, cont'd.
3
What constitutes an object?


a class is:
 a module (a chunk of executable code)
 a type definition (describes data and behavior for a
new type of objects)
What is the difference between a class and an object?
What are the features of an object, according to Riel?
An object has:
 identity
 state
 behavior
 published interface
(memory address)
(fields)
(methods)
(user's view)
4
Qualities of modular software

decomposable


composable


one piece can be examined in isolation
has continuity


pieces are useful and can be combined
understandable


can be broken down into pieces
reqs. change affects few modules
protected / safe

an error affects few other modules
5
Interface and implementation

What is the "public interface" of an object?
What is the "private implementation"?




public interface: data and behavior of the object that can
be seen and executed externally by "client" code
private implementation: internal data and methods in the
object, used to help implement the public interface, but
cannot be directly accessed
client: code that uses your class/subsystem
example: radio
Public interface is the speaker, volume buttons, station dial
Private implementation is the guts of the radio; the
transistors, capacitors, voltage readings, frequencies, etc.
that user should not see
6
Encapsulation


Heuristic 2.1: All data should be hidden within its
class.
encapsulation: hiding the private state and behavior
within a class and its objects

What benefit do we receive from encapsulation? Why not
just use public fields and methods?




encapsulation promotes abstraction: ability to focus on task at
hand and not on specific unnecessary details
if data is public, it can never be changed
(it becomes part of published interface)
public data exposes the client to unnecessary details about how the
class is implemented
example: point class with x, y vs. r, theta (fig 2.3 p14)
7
Dependency on clients


Heuristic 2.2: Users of a class must be dependent on
its public interface, but a class should not be
dependent on its users.
example: GradeCalculator class with 3 methods:




readGradeInput
computeGrades
showGradeOutput
if the 3 methods are not called in exactly this order,
GradeCalculator code crashes! Solutions?



have computeGrades or showGradeOutput call their preceding
methods if that hasn't been done already
combine these methods into only one public method that calls all 3 in
order
make each function return output that is used as input to next func 8
Classes' protocols/interfaces

Heuristic 2.3: Minimize the number of messages in
the protocol of a class.


Heuristic 2.4: Implement a minimal public interface
that all classes understand.



example: a LinkedList class with too many methods makes it
hard to find a common operation, such as merge with
another linked list (in paper, this was operator +)
example: implement toString for all classes
example: implement equals and compareTo as appropriate
protocol: another word for "public interface"
9
Some methods should be private!



Heuristic 2.5: Do not put implementation details such as
common-code private functions into the public interface of a
class.
Heuristic 2.6: Do not clutter the public interface of a class
with items that users of that class are not able to use or are not
interested in using.
example: LinkedList class has add and remove methods that
both advance the list to the proper linked node to add/remove,
then performs the operation. How should we design this?


use a common helper named getNodeAt(int index) that advances the list
to the proper node and returns that node
make the helper getNodeAt a private method so client code does not
see it and cannot call it
10
Minimizing public interface

Some ways to minimize a class's protocol:


Make a method private unless it needs to be public.
Only supply getters (not setters) for fields' values if you can
get away with it.


When writing a class that wraps up a data structure, don't
replicate that data structure's entire API; only expose the
parts you absolutely need.



example: Card object with rank and suit (get-only)
example: Deck class holds a List of cards, but the game only shuffles
and draws the top card, so rather than having a getCard(int index),
add, remove, etc., just have shuffle() and drawTopCard() methods
example: If your Game has an inner list or hash map of Players,
supply just an Iterator or a getPlayerByName(String name) method
Use a Java interface that holds only the needed methods
from the class, and then refer to your class by the interface
type in client code.
11
Cohesion and coupling

What do the terms "cohesion" and "coupling" mean?
Are they good or bad things?


cohesion: how complete and closely related things are
within your class (a good thing)
Heuristic 2.8: A class should capture one and only
one key abstraction.

(bad) example: PokerGame class that holds all the players,
holds an array representing the card deck, stores all bets
and money, does the logic for each betting round...
 Better way to do it?
12
Coupling

coupling: how much your classes are connected to
each other and depend on each other (can be a bad
thing)
nil coupling: no connection at all
 export coupling: one class depends on public interface of
another
 overt coupling: one class uses another's innards legally
(C++ friend classes, Java subclasses using protected stuff)
 covert coupling: using another class's inner details without
permission (hard to do this in Java)
Heuristic 2.7: Classes should only exhibit nil or export
coupling with other classes, that is, a class should only use
operations in the public interface of another class or have
nothing to do with that class.


13
Reducing coupling

Some ways to reduce coupling:

combine two classes that don't represent a whole
abstraction


make a coupled class an inner class



example: Bet and Round
example: list and list iterator
example: GUI frame and event listener
provide more unified communication points
between subsystems, so that one subsystem does
not need to communicate with every piece of
another subsystem

example: providing convenience methods (newGame,
reset, ...) in PokerGame class so that GUI does not need
to manually refresh the players, bets, etc.
14
Related data and behavior

Heuristic 2.9: Keep related data and behavior in one
place.



avoids having to change two places when one change is
needed
example: Should a Poker game Player class remember
whether that player is in the game, what that player's
current bet is, etc? Or should the Game class remember
who is in the game, the Bet class remember every player's
current bets, ...?
Heuristic 2.10: Spin off nonrelated behavior into
another class (i.e., noncommunicating behavior).

example: code to do save/load of dictionary for anagram
game
15
Roles of objects

Heuristic 2.11: Be sure the abstractions that you
model are classes and not simply the roles objects
play.

example: to model a family tree, should we make classes for
Father, Mother?



no; make Person objects with (field values) of FATHER, MOTHER, ...
example: Should we make a Club, Diamond, Heart, Spade
class to represent each suit of cards?
example: Should we make a FirstBetter class that represents
the player who is currently betting first in our card game?
16
Interfaces

interfaces should be used when you want the
following:




polymorphism: ability to treat different types of objects
the same way (can call same method on two objects and get
different results, based on their types)
no code sharing: each class implements the methods in the
interface in its own way
example: Java's collection framework uses interfaces for abstract data
types (ADTs). The List interface is implemented by LinkedList and
ArrayList; the Map interface is implemented by HashMap and TreeMap.
The Iterator interface provides iteration over each of these data
structures.
example: The Comparable interface lets us define how to order objects
of our type; objects of different types can be compared in different
ways.
17
Inheritance

inheritance should be used when you want the
following:



code sharing: subclass's object receives all code from
superclass's objects; those methods can now be called on it
substitutability: client code can use subclass's object in
any situation that a superclass object was expected, and
expect the same results to occur
example: In Java Swing, a JComponent is a superclass that
represents any graphical component. This class stores
common features like size, location, color, and font. More
specific JComponents such as JButton and JPanel extend
JComponent to share these features. Any JComponent may
be substituted for another in a variety of cases, such as
being added to a frame on the screen.
18
Inheritance vs. delegation



If we write a Stack class that is really just a variation on a List,
should the Stack extend List?
We want a class that models a sorted linked list, so that when
any element is added to the list, it will be added in-order and
the list's contents will always be sorted. Should
SortedLinkedList extend LinkedList?
We're writing shape classes. Should Square extend Rectangle?

In all cases, no.
We do not want the user to be
able to arbitrarily call add or
remove on the Stack.
Also, the SortedLinkedList
cannot substitute for a normal
LinkedList (result of an add
differs), so it should not extend
it. Both should delegate to an
inner List object they maintain.
List
+add()
+remove
Stack
Stack
+push
+pop()
+top()
List
remov
add()
+push
+pop()
+top()
19
Positioning common code

We are designing our collection framework, and we
want the ability to sort a list. The list could be a
linked list or an array list. LinkedList and ArrayList
both implement the interface List, but they currently
have no common superclass. Where should we put
the sorting functionality?

Consider a new class called Collections or CollectionUtilities.
This class can have a static method sort that takes a List as
its argument, then sorts it. (This is what Java's collection
framework does!)
20
Interface, inheritance example

We want it so that some objects can be allowed to be exported on the
network, and some objects can be allowed to be stored locally. All types of
objects would export or store themselves in the same way. An object can
be exportable, storable, or both. Some objects also can be cloned, and each
type of object clones itself in a different way. Lastly, some objects are
output buffers (should be directly treatable as an output buffer) and should
implement common output buffer behavior that is always done the same
way. A class OutputBuffer already exists that implements this functionality,
but we do not want users creating objects of this class. What combination
of superclasses, interfaces and delegation should be used in this system?




use methodless interfaces named Exportable and Storable; classes that
can be used in these ways implement these "tagging" interfaces
delegate task of exporting and storing to an Exporter or Storer class
whose methods will take arguments of type Exportable or Storable
use an interface Cloneable that has a method clone() that the class must
implement to specify how to clone it
use an abstract superclass named OutputBuffer, and extend it when a
class wants to be an output buffer
21