1.7 Object-Oriented Programming and Software Engineering

Object-oriented programming is an evolutionary development in software
engineering. The foundation for many object-oriented languages were
established by decades of software engineering experience that
motivated the invention of language features such as closed
procedures, modules and abstract data types. Also important were the
widely recognized value of such software engineering techniques as
information hiding, encapsulation, strict enforcement of interfaces,
and layering.

Object-oriented programming address (at least) the three major
software engineering goals shown in this figure:

Software Engineering Goals

The language features that address these issues are those of objects,
classes, inheritance, polymorphism, templates, and design patterns.

Reusability is an important issue in software engineering for at least
two major reasons. First reusability is one means to cope with the
pressures of producing ever larger and more functional systems in an
ever decreasing development cycle (time to market). Reusability allows
developers to be more efficient because the same code can be developed
once and used in many different applications. Second, reliability can
be improved by reusing previously developed, and previously tested,
components. The development of new code entails the additional costs
in time and money of testing, validation, and verification of the new
code. Much of these expenses can be avoided by using "off-the-shelf"
components.

Software reuse is certainly not a goal unique to object-oriented
programming. While libraries of procedures proved this approach to be
useful, in practice procedures were too primitive a unit to promote
extensive reuse. Objects and classes are more sophisticated mechanisms
for achieving software reuse because they bind together more
completely all the aspects of an entire abstraction. Therefore, the
abstraction can more easily be transported across applications. Any of
the forms of generalization also contribute to reuse. A class in an
inheritance hierarchy can be reused directly when it serves as a
generalized base class from which a new class is derived by
specialization. Templates can be reused by supplying different
parameters for the template arguments. Design patterns allow design
experience and success to be reused across designers.

Extensibility in software is important because software systems are
long-lived and are subject to user's demands for new features and
added capability. Object-oriented programming can help to satisfy
this need through inheritance. Recall that inheritance is a
generalization/specialization hierarchy. Referring to the Window
hierarchy discussed earlier, extensibility is possible in two
ways.
The first way in which a generalization/specialization hierarchy
supports extensibility is that any new attributes or behavior that is
added to a more generalized concept (e.g., Window) will automatically
become part of the attributes and behavior of its specializations
(e.g., Frame, Item, Button). For example, as shown below, if the
Window abstraction is enhanced to include a color with which the
Window would be displayed on the screen, then the attribute
"currentColor" and the behavior "setColor" might be added to
Window. It would then be possible to manipulate the color of a Window
but all its specializations as well.

Adding new Attributes and Behavior

The second way in which a generalization/specialization hierarchy
supports extensibility is that the hierarchy itself can be
extended. New additions can be made under any existing node. For
example, as shown below, the TextWindow might be specialized to a
HyperTextWindow by including additional attributes and additional
behavior that distinguishes ordinary words from those words that are
hyperlink and can be clicked-on to transfer to another place in the
text.

Adding new Specialized Classes

Flexibility in software systems means, in part, that additions, variations or
modification can be made without the need to modify numerous places
in the system's code. Historically, many software systems were very
brittle in that the addition of a small change could only be
accomodated by making modifications in many, and often aparrently
unrelated, parts of the existing system. This brittle property stood
in marked contrast to the prevaling notion that, nlike hardware
systems, software system were supposed to be extremely
maleable and changes can be made easily.

Object-oriented programming contributes to flexibility in two
ways. First, the separation of an interface from its implementation
allows the user of the interface to remain unaffected by changes in
the implementation. Thus, a modification can be made to the
implementation (e.g., to improve its efficiency or reliability)
without requiring any changes in the code that uses the
interface. Second, polymorphism allows variations and additions to be
made to the set of classes over which the polymorphism applies. For
example, referring to the Window hierarchy, consider adding a new kind
of interaction Item, a RadioButton. Since Items can be placed in a
Panel, it would seem necessary to modify the Panel to allow a Panel to
manipulate the newly created RadioButton. However, the Panel can use
polymorphism so that the Panel's algorithms only rely on the more
general attributes and behavior of an object (i.e., that it is a kind
of Item) and does not need to be aware of the exact "type" (i.e.,
RadiButton) of the object. Using this approach, the Panel can be
designed to operate on Items. Any newly created Item, even one - like
the RadioButton - that is created after the Panel is already written,
automatically can be manipulated by a Panel without changing the code
of the Panel.