Documente Academic
Documente Profesional
Documente Cultură
by Grady Booch
Department of Astronautics and Computer Scienc e
USAF Academy, Colorado 80840
ABSTRACT
The current software depression is characterized
by software that is late, erroneous, and costly .
Experience indicates that the application o f
appropriate design methodolgies, embodied in a
high-order language, is appropriate in combattin g
this depression. In particular, this paper
describest an object-oriented design methodology ,
using Ada- as the implementation language .
1 . THE SOFTWARE DEPRESSION
Ever since that fateful day when Ada Augusta first pu t
quill pen to paper to program Babbage' s Analytic Engine, th e
world has experienced a software crisis . A certain computer
scientist with great insight has observed that something
that has gone on this long can' t be called a crisis, bu t
instead is really a depression . In particular, Dijkstra ha s
described the problem as one of organization of complexity ,
rather than (mis) use of technology [1 ] . Clearly, curren t
technology has opened problem domains with solutions beyond
the understanding of a single human . The quantitative
effects of this depression are well documented, but gen-
erally point to software systems (and programmers) that ar e
late, expensive, unreliable, and often in disagreement with
their own specifications .
One approach to combat this depression is the applica-
tion of an appropriate design methodology, embodied in a
modern high-order language . The key concept here is to use
a methodology that controls the complexity of the problem
solution . Ross, Goodenough, and Irvine have describe d
several design principles that support this goal, namely
[2 ]
:
1 Ada is a trademark of the Department of Defense ,
Ada Joint Program Office .
I-3 . 64
e Modularity
o Abstraction
o Localization
e Information hiding
o Completenes s
Confirmability
The current idea of functional top-down design sup-
ported by structured programming falls short in supporting
information hiding and enforcing abstraction [3] . Such a
methodology is too imperative, and fails to control the com-
plexity of data structure design .
2 . AN OBJECT-ORIENTED METHODOLOGY
We can contrast top-down functional design and object -
oriented design by studying "the criteria for decomposing a
system into modules : "
If a designer cannot
2 In the book, Psycholinquistics (Prentice-Hall ,
1 97 8), Foss and Haker cite the linguist Benjamin Whor f
who goes so far as to hypothesize that a language has
considerable effect on what one can think .
I-3 . 66
understand a design expressed in a natural manner, the n
there are underlying conceptual problems that no computer
language or axiomatic system can cure .
For an implementation to reflect a design structure, we
need a language with a primitive set of tools, and a mechan-
ism to create higher level at abstractions (the property of
extensibility) . Ideally, we would like a language that sup-
ports and enforces the six design principles mentioned ear-
lier .
In this regard, Ichbiah has referred to the evolutio n
of modern programming languages [8] . In the first genera-
tion, there existed languages such as FORTRAN that provided
tools of mathematical expression . Next, Faith ' structured'
languages such as ALGOL, tools for (algorithmic) control
were refined . The third generation, starting with Pascal ,
provided rich tools for expression of data structures . In
Ada, the elements of all three generations are present, and
in addition we are given (through the package mechanism) a
tool to enforce our abstractions within the language . As a
result, Ada provides an almost ideal implementation language
for the object-oriented design methodology . Conversely ,
this methodology allows a user to exploit some of the power-
ful elements of Ada, including the packaging and tasking
models .
4 . A DESIGN EXAMPLE
To illustrate the object-oriented methodology, we wil l
present the problem of counting the leaves of a binary tree ,
an example originally created by Abbott [6] . We have
reworked the design slightly, and have added the Ada imple-
mentation to illustrate some key points . Referring back to
our methodology, we have :
4 . 1 Define the Problem
A binary tree is a data structure in which each nod e
has two or fewer branches . A tree is either a leaf (no
branches), or consists of two sub-trees . If a tree is just
a leaf then
LEAVES (TREE) = 1
and if it consists of two subtrees then
LEAVES (TREE)
e
LEAVES (TREE1 ) + LEAVES (TREE2 )
1 -3 . 67
Our task is to develop a system that counts the leaves (ter-
minal nodes) of a given tree .
4 . 2 Develop an Informal Strategy for the Abstract World
There are many ways to count the leaves . For example ,
we could traverse the tree, but this is an imperative metho d
that requires us to know at a high level how the elements of
a tree are connected (an implementation detail) . Instead, we
will use an algorithm that appeals to an intuitive approach ;
such an approach should directly reflect our abstract view
of the world . We will assume only that we have the thre e
basic control structures (sequential, conditional, itera-
tive) plus a facility for defining operations and object s
for our abstract world (extensibility) . Given these con-
straints, we can present our informal strategy.
We will keep a pile of the parts of the tree tha t
have not yet been counted . Initially, we will ge t
a tree and put it in the empty pile . The count of
the leaves is initially set to zero . As long a s
the pile is not empty, we will repeatedly take a
tree of . the pile and examine it. If the tree
consists of a single leaf, then we will incremen t
the leaf counter and throw away the tree . If th e
tree is not a single leaf but instead consists o f
two subtrees, we will split the tree into its left
and right subtrees and put them back on the pile .
Once the pile is empty, we will display the count
of the leaves.
4 . 3 Formalize the Strategy
The next step is to refine our view of the abstract world ,
leading eventually to an Ada implementation .
4 . 3 . 1 Identify Objects and Their Attributes
This is a simple task ; we will repeat our informal strategy
in the abstract world, underlying the applicable nouns and adjec-
tives :
We will keep a pile of the parts_of__ the tree that
have not yet been counted . Initially, we will ge t
a tree and put it on the empty pile . The count_of f
the leaves is initially set Lo zero. As long as
Ehe pile is not empty, we will repeatedly take a
tree off the file and examine If the tree
consists of a single leaf, then we will increment
I-3 . 68
the leaf_coujr and throw away the tree. If th e
tree is not a single leaf but instead consists o e
two subtrees, we wa
LEAF COUNT
o PILE
SUBTREE LEFT
SUBTREE RIGHT
o TREE
as instances of abstract data types .
Recall that a type characterize s
o A set of values
o Operations applicable to the se t
By ' primitive type, ' we mean an elementary tool tha t
describes the structure of data as part of an implementatio n
language . In Ada, primitive types include the enumeration ,
integer, real, array, record, access, private, task, sub -
type, and derived types. An abstract data type, on th e
other hand, comes from our high-level abstraction of th e
problem, and is (usually) not directly available in th e
implementation language . For example, our program migh t
manipulate a deck of cards representing an instance of an
abstract data type . The set of values that are important to
our abstraction might be the face value of each of 52 cards .
Notice that the size, weight, etc . , of the deck are not
critical to this abstraction ; these details are hidden. Th e
operations we might expect include shuffling the deck and
drawing a card . By abstracting the values and operation s
from the problem space, we have thus described a new type
built from the primitive types . As we shall see, Ada per-
mits us to create and enforce such abstractions . We should
add that the ability to enforce our logical abstractions i s
a feature that sets Ada apart from language like PL/l o r
Pascal. We may create abstractions in our programs, but th e
rules of PL/l or Pascal do not prevent a program fro m
violating the logical property of our objects . For example ,
we may create an abstract stack in either language, and pro -
vide the operation POP and PUSH . However, PL/l or Pascal
cannot encapsulate the type, and a programmer may violate
our stack model by directly referring to the fifth element
of the stack.
I-3 . 69
At this point in our design process, we have named th e
objects that are of interest to us, and we are ready t o
enumerate the applicable operations .
4 . 3 . 2 Identify Operations on the Objects
This too is a simple task ; we will repeat the abov e
process, this time underlining the applicable verbs an d
adverbs :
We will keep a pile of the parts of the tree tha t
have not yet been counted . Initially, we will ge
a tree and put in on the empty pile . The count of
the leaves is initially set_to_zero. As long a s
the pile is not empty, we will repeatedly take a
tree off the pf
and examine it .
ICEthe_ tree
consists of _a singleleaf, then we will increment
the-leaf counter and throw away the tree. If th e
tree is not a sin le leaf but instead consists o f
two su trees, we will shit; the tree into its lef t
and right subtrees and put. them back on the pile .
Once the pile is empty, we will display the count
of the leaves .
Thus, our operations ar e
e LEAF COUNT
--DISPLAY
--INCREMENT
--ZERO
e PILE
I S_NOT_EMPTY
--PUT
--PUT INITIAL
--TAKE
e SUBTREE LEFT SUBTREE RIGHT, TREE
--GET_INITIAL
--IS SINGLE LEAF
--SPLIT
--THROW AWAY
I-3 .70
4 .3 .3 Establish the Interface s
At this point, we have startedour design by describing
the high-level objects as instances of abstract data types .
We can complete our first level of design by describing the
relationship of these objects with each other . Since large
solutions are often difficult to comprehend from just text,
it is useful to express such a design graphically . Else-
where we have discussed the use of such symbols [9], bu t
briefly, these symbols include
UNDEFINED OR HIDDE N
ENTITY
SUBPROGRAM
SPECIFICATION
BODY BODY
TAS K
SPECIFICATION
PACK AGE
Thus, we have a representative for each Ada program unit . For
the COUNT LEAVES ON BINARY TREE problem, our design can be
_
represented as
The directed lines in this figure indicate the visibility among
the objects. Thus, the TREE_PACK AGE is visible to th e
PILE . PACK AGE, but not vice versa .
A question of style arises . How do we best use Ada pack-
ages? The answer is that a number of applications is appropri-
ate . Packages represent a logical collection of computational
1 -3 . 7 2
resources and with our object-oriented methodology can be used to
encapsulate :
o A named collection of declarations
e A named collection of subprograms
o An abstract data type
o An abstract state machine
In our example, we will create abstract data types as a tem-
plate for the LEAF COUNT, PILE, SUBTREE LEFT, SUBTREE RIGHT, and
TREE objects . As a matter of style, we name each package as a
common noun representing the eventual object class . In the fol-
lowing package specifications, note also the names of the actua l
parameters . Careful selection of names here will pay off later ,
as we shall see . Finally, when naming subprograms, we use th e
style of naming procedures as active verbs, and boolean functions
with verbs of the form to be .
In the following set of compilation units, note that th e
package specifications indicate the interface to the abstrac t
types. By declaring the types as limited private or private, th e
Ada semantics state that the onl operations applicable to tha t
type are those listed in the visible part of the specification .
Thus, Ada enforces the abstraction. In addition, the implementa-
tion of the type is hidden form the user in the package body i n
direct support of the principle of information hiding .
For
the
LEAF COUNT,
which
in
an
instance
of
a
COUNTER PACKAGE OBJECT TYPE, we can implement the interface as :
(COUNTER : in
OBJECT TYPE) ;
procedure INCREMENT (COUNTER : in out OBBJECT~TYPE) ;
procedure ZERO
(COUNTER : out
OBJECT_TYPE) ;
private 3
end COUNTER PACK AGE
Continuing, we may define the SUBTREE LEFT, SUBTREE_RIGHT,
and TREE objects as instances of a TREE_PACK AGE . OBJECToTYPE:
3 The private part would normally show the imple-
mentation, but we will omit it here for simplicity .
I-3 . 7 3
package TREE_PACK AGE i s
type OBJECT_TYPE is private ;
procedure GET INITIAL
(TREE
: out
OBJECT TYPE) ;
function IS SINGLE LEAF (TREE
: in
OBJECTTYPE)
return BOOLEAN ;
(TREE
OBJECT TYPE ;
RIGHT INTO : out
OBJECT TYPE ;
(TREE
: in out OBJECT_TYPE) ;
For the PILE, we could have used a generic package, bu t
since we will use PILE only to keep trees, we may write th e
interface simply as :
with TREE PACKAGE;
package PILE_PACKAGE is
tree OBJECT_TYPE is limited private ;
function
: in out OBJECT_TYPE) ;
procedure PUT~INITIAL (TREE : in out TREE PACK AGE. OBJECTWTYPE ;
ON out OBJECTTYPE) ;
procedure TAK E (TREE : out TREE_ PACK AGE. OBJECT_TYPE ;
OFF
Yourdon,
E.
Managing
the
Structured
Tec__niques ,
Prentice-Hall, Inc . , New Jersey, 1 97 9 . -~
5.
Science Applications,
Inc . ,
McLean Virginia, 1980 .
7 . Linger, R. C . , Mills, H. D . , and Witt, A . I . Structured
Programming: