Abstraction
When you set out to design a Java program, you
have to create abstractions. You are faced with a problem domain and
(with luck) a specification, and you have to architect [bv: is
architect a verb?] a solution. (The problem domain is the
subject area of a particular programming effort, such as "accounting,"
"elevator control," or "word processing.") Given that Java is an
object-oriented language, you will likely want to perform an
object-oriented design. In the process, you will end up with
abstractions in the form of objects, types, attributes, and behaviors.
The object-oriented design process involves the following three tasks:
- dividing the problem domain into types of objects,
- modeling the relationships between the types, and
- modeling the attributes and behaviors of each type.
These
tasks are not listed in any particular order. Most likely, you will
perform these tasks iteratively throughout the design process.
In
an object-oriented design, you identify the fundamental objects of the
problem domain, the "things" involved. You then classify the objects
into types by identifying groups of objects that have common
characteristics and behaviors. The types of objects you identify in the
problem domain become "types" in your solution. The program you write
will create and manipulate objects of these types. By naming the types
in your solution after the types in the problem, you build a vocabulary
for expressing the solution out of the language you would use to
describe the problem.
In addition to types that correspond to
elements in the problem, the "problem domain types," your solution will
likely have types that don't correspond to anything in the problem
domain. For example, most programs will require types that deal with
data management and user interface. An example of a data-management
type is a hash table. You might use a hash table object in your program
to speed lookup of a set of objects, even though there is no hash table
object in the problem domain. The objects you are looking up in the
hash table, however, might represent objects that exist in the problem
domain. Some examples of user interface types might be button, window,
and dialog.
The fundamental task of abstraction in an
object-oriented design is to identify objects in the problem domain and
then to classify the objects into types. As you divide the problem
domain into types, you will to some degree model the relationships
between the types as well. Objects can have three kinds of
relationships:
- the has-a relationship
- the is-a relationship
- the uses-a relationship
The has-a relationship
means that one type of object contains another or is composed of
another. Some examples are: a car has-an engine, a bicycle has-a wheel,
and a coffee cup has coffee. The has-a relationship is modeled with
composition, which is discussed in Chapter 6.
The is-a relationship
means that one type of object is a more specific version of a general
type. Some examples are: a car is-a vehicle, a bicycle is-a vehicle,
and a coffee cup is-a cup. The is-a relationship is modeled with
inheritance, which is also discussed in Chapter 6.
The uses-a relationship
means that during some activity, one type of object uses another type
of object. Some examples are: a car uses-a squeegee (during a
window-washing activity), a bicycle uses-a pump (during a tire-pumping
activity), and a coffee cup uses-a stirrer (during a stirring
activity). The uses-a relationship will be discussed further in Chapter
?? [bv: which chapter?].
Along with dividing the problem domain
into types and modeling their relationships, you must define attributes
and behaviors that will characterize each type in the solution.
The attributes of a type define the nature of the state of objects of that type. An object's state
is composed of values for all the attributes of the type. For example,
two possible attributes for a bicycle type are speed and direction. An
object of type bicycle would therefore have a state that is composed of
values for speed and direction. Note that an object's state (the values
of its attributes) can change over the lifetime of the object. A
bicycle object, for example, could have a state of 15 mph and north at
one point in time. Later, that same object could have state 10 mph and
south.
In object-oriented thinking, interaction between objects
is modeled as messages sent between objects and the action that objects
take as a result. When you model the behavior
of a type you define a set of messages that objects of that type will
accept, and the actions that objects of that type will take upon
receipt of those messages. The set of accepted messages and the
resulting actions constitute services that are offered by the object.
As
the designer of a type, you decide what an object of that type will do
when it receives a message. Messages contain information, and an object
can use the information contained in a received message along with the
information represented by its own current state, to decide what to do.
It may do nothing. It may send messages to other objects. It may change
its own state. It may return some information to the message sender. Or
it may do all of these things.
In computer science circles, the
term "message" is often associated with asynchronous messaging, in
which received messages can queue up and be processed by the recipient
at some later time. In this object-oriented context, however, a message
is simply a request coupled with some information that is passed to an
object. In general, an object begins to process a message immediately
upon receipt and potentially returns a reply to the sender. A message
can have an effect that is delayed (similar to asynchronous messaging),
but creating such a delayed effect is an option of the message
recipient.
These design activities are processes of abstraction
because out of all the elements of the problem domain, you are
selecting only those that are important. As a result, in any one design
you will likely ignore many elements of the problem domain. In your
solution, you won't model every type of object you can possibly
identify in the problem domain, only those that matter to your
solution. Likewise, you won't model every attribute and every behavior
of the types of objects you have chosen to represent in your solution,
just those attributes and behaviors that are important to your
solution. In a different problem domain, you might model different
attributes and behaviors of the same types of objects. Thus, you are
abstracting: pulling out what you feel is important about the problem
domain, and using only those elements in your solution.
Designing a Virtual Café
As
an example of an object-oriented design with the Java programming
language, imagine you are designing a virtual café, a place in
cyberspace where guests can sit at small tables, sipping virtual cups
of coffee, and chatting with one another. The primary function of the
café is that of a chat room: a place where people separated by
(potentially vast) physical distances, but connected to the same
network, can get together and converse. To make your chat room more
inviting, you want it to look like a café. You want each participant to
see graphical representations ("avatars") of the other people in the
café. And to make the participant's experience more real, you want the
people to be able to interact with certain items in the café, such as
tables, chairs, and cups of coffee.
Identifying Types
To
start your design process, visualize your virtual café on an average
busy day. What objects do you see? Perhaps you see guests, tables and
chairs, coffee cups, coffee, pitchers of milk, packets of sugar, coffee
stirrers, and the café itself. These are the types of objects in your
problem domain. By describing them in a human language, you are already
classifying them, grouping related objects together. You may have 100
different coffee cups in your café--all distinct objects--but you place
all 100 of them into the "coffee cup" category when you say, "I see 100
coffee cups." This is the first step in an object- oriented design:
identifying objects in the problem domain, and grouping them by type.
As
the designer, you must decide which objects to group into which
categories. Just as describing a scene in human language is not an
exact science--you have to pull out what's important and focus your
description on that--neither is object-oriented design an exact
science. There are many ways to slice up a given problem domain into
objects and types. Because of this, you must focus on the types of
objects you think will be most important in your solution. These will
be the types that have the greatest interaction. For example, in the
case of your virtual café, you may have artsy drawings hanging on the
walls, but if those drawings do nothing but hang there, then perhaps
they shouldn't be awarded with their own type. They can just be a
characteristic of your café type.
So what types of objects are
the most important in the virtual café? Ask yourself what kind of
objects are involved in the activities of your café. Guests sit on
chairs at tables and chat with their neighbors. They buy cups of
coffee, add milk or sugar to them, swirl the result with a stirrer, and
drink. If these are the primary activities that go on in your problem
domain, then the types of objects involved should be what you most
concern yourself with in your solution: guests, tables, chairs, coffee
cups, coffee, milk, sugar, stirrers, and the café itself.
Each
of these objects interacts with other objects. Chairs may host a guest
or be empty. Tables can have different numbers of chairs. Both tables
and chairs can be moved around the café. Tables can be moved together
to accommodate large groups of guests. Coffee cups accept coffee, milk,
sugar, and a swirling stirrer. They also release their contents sip by
sip to the drinker, or can spill their contents all at once onto the
table, onto the floor of the café, or more alarmingly, onto a guest.
Although
the objects you group together will share characteristics and
behaviors, they will usually not be identical copies of each other.
There are many objects in your everyday experience that you would call
coffee cups--some are made of styrofoam, some of ceramic; some are big,
some small--but you still recognize them as coffee cups because of the
characteristics and behaviors they have in common. Mainly, they hold
coffee for you to drink. They allow you to add extras, such as sugar or
milk, and to insert a stirrer to swirl the components into the perfect
drink to suit your palette. If you knock them over, they'll spill their
contents. The first step of object-oriented design, therefore, is
creating abstract categories, such as "coffee cup", and placing
different objects, each of which may have their own unique qualities,
into the same category.
The first part of the process of
abstraction usually involves not simply deciding upon lone types, but
upon inheritance hierarchies of types. An inheritance hierarchy
is a diagram showing the inheritance (is-a) relationships between
types. Thus, as you determine types you will usually model is-a
relationships with inheritance. To start with, however, this discussion
will keep it simple and just focus on lone types. Inheritance will be
discussed in Chapter 6.
Download