The Object Model
Object-oriented technology is built on a sound engineering foundation,
        whose elements we collectively call the object model of development or
        simply the object model. The object model encompasses the principles of
        abstraction, encapsulation, modularity, hierarchy, typing, concurrency,
        and persistence. By themselves, none of these principles are new. What
        is important about the object model is that these elements are brought
        together in a synergistic way.
1   The Evolution of the Object Model
        Object-oriented development did not spontaneously generate itself from
        the ashes of the uncounted failed software projects that used earlier
        technologies. It is not a radical departure from earlier approaches.
        Indeed, it is founded in the best ideas from prior technologies. In this
        section we will examine the evolution of the tools of our profession to
        help us understand the foundation and emergence of object- oriented
        technology.
          As we look back on the relatively brief yet colorful history of software
          engineer- ing, we cannot help but notice two sweeping trends:
            1. The   shift in focus from programming-in-the-small             to
               programming-in-the- large
            2. The evolution of high-order programming languages
          Most new industrial-strength software systems are larger and more
          complex than their predecessors were even just a few years ago. This
          growth in complexity has prompted a significant amount of useful
          applied research in software engineering, particularly with regard to
          decomposition, abstraction, and hierarchy. The devel- opment of more
          expressive programming languages has complemented these advances.
          The Generations of Programming Languages
          Wegner has classified some of the more popular high-order
          programming lan- guages in generations arranged according to the
          language features they first intro- duced By no means is this an
          exhaustive list of all programming languages.)
            ■   First-generation languages (1954–1958)
        FORTRAN I Mathematical
        expressions ALGOL 58
                       Mathematical
        expressions Flowmatic
                       Mathematical
        expressions IPL V Mathematical
        expressions
  ■   Second-generation languages (1959–1961)
        FORTRAN II Subroutines, separate
        compilation ALGOL 60 Block structure,
        data types COBOL Data description, file
        handling
        Lisp           List processing, pointers, garbage collection
  ■   Third-generation languages (1962–1970)
        PL/1           FORTRAN + ALGOL + COBOL
        ALGOL 68 Rigorous successor to
        ALGOL 60 Pascal Simple successor to
        ALGOL 60
        Simula         Classes, data abstraction
  ■   The generation gap (1970–1980)
      Many different languages were invented, but few endured.
      However, the fol- lowing are worth noting:
        C              Efficient; small
        executables FORTRAN 77 ANSI
        standardization
Let’s expand on Wegner’s categories.
  ■   Object-orientation boom (1980–1990, but few languages
        survive) Smalltalk 80       Pure object-oriented
        language
        C++                  Derived from C and Simula
        Ada83                Strong typing; heavy Pascal influence
        Eiffel               Derived from Ada and Simula
  ■   Emergence of frameworks (1990–today)
      Much language activity, revisions, and standardization have
      occurred, lead- ing to programming frameworks.
        Visual Basic         Eased development of the graphical user
        interface
                             (GUI) for Windows applications
        Java                 Successor to Oak; designed for portability
      Python               Object-oriented scripting language
      J2EE                 Java-based framework for enterprise
      computing
      .NET                 Microsoft’s object-based framework
      Visual C#            Java competitor for the Microsoft .NET
    Framework
      Visual Basic .NET    Visual Basic for the Microsoft .NET
      Framework
This first generation of high-order programming languages therefore
represented a step closer to the problem space and a step further away
from the underlying machine.
Among second-generation languages, the emphasis was on algorithmic
abstrac- tions. By this time, machines were becoming more and more
powerful, and the economics of the computer industry meant that more
kinds of problems could be automated, especially for business
applications.
By the late 1960s, especially with the advent of transistors and then
integrated cir- cuit technology, the cost of computer hardware had
dropped dramatically, yet pro- cessing capacity had grown almost
exponentially. Larger problems could now be solved, but these
demanded the manipulation of more kinds of data. Thus, third-
generation languages such as ALGOL 60 and, later, Pascal evolved
with support for data abstraction. Now a programmer could describe
the meaning of related kinds of data (their type) and let the
programming language enforce these design decisions. This generation
of high-order programming languages again moved our software a step
closer to the problem domain and further away from the underlying
machine.
What is of the greatest interest to us is the class of languages we call
object-based and object-oriented. Object-based and object-oriented
programming languages best support the object-oriented
decomposition of software. The number of these languages (and the
number of “objectified” variants of existing languages) boomed in the
1980s and early 1990s. Since 1990 a few languages have emerged as
mainstream OO languages with the backing of commercial
programming tool vendors (e.g., Java, C++). The emergence of
programming frameworks (e.g., J2EE, .NET), which provide a
tremendous amount of support to the programmer by offering
components and services that simplify the common and often mun-
dane programming tasks, has greatly boosted productivity and
demonstrated the elusive promise of component reuse.
The Topology of First- and Early Second- Generation Programming
Languages
Let’s consider the structure of each generation of programming
languages. In Figure 1, we see the topology of most first- and early
second-generation programming languages. By topology, we mean the
basic physical building blocks of the language and how those parts can
be connected. In this figure, we see that for languages such as
FORTRAN and COBOL, the basic physical building block of all
applications is the subprogram (or the paragraph, for those who speak
COBOL).
Applications written in these languages exhibit a relatively flat physical
structure, consisting only of global data and subprograms. The arrows in
this figure indicate dependencies of the subprograms on various data.
During design, one can logically separate different kinds of data from
one another, but there is little in these languages that can enforce these
design decisions. An error in one part of a pro- gram can have a
devastating ripple effect across the rest of the system because the global
data structures are exposed for all subprograms to see.
             Data
           Subprograms
     Figure 1 The Topology of First- and Early Second-Generation
                    Programming Languages
When modifications are made to a large system, it is difficult to
maintain the integrity of the original design. Often, entropy sets in:
After even a short period of maintenance, a program written in one of
these languages usually contains a tremendous amount of cross-
coupling among subprograms, implied meanings of data, and twisted
flows of control, thus threatening the reliability of the entire sys- tem
and certainly reducing the overall clarity of the solution.
The Topology of Late Second- and Early Third-Generation
Programming Languages
By the mid-1960s, programs were finally being recognized as
important intermediate points between the problem and the computer .
“The first software abstraction, now called the ‘procedural’ abstraction,
grew directly out of this pragmatic view of software. . . . Subprograms
were invented prior to 1950, but were not fully appreciated as
abstractions at the time. . . . Instead, they were originally seen as labor-
saving devices. . . . Very quickly though, subprograms were
appreciated as a way to abstract program functions” .
The realization that subprograms could serve as an abstraction
mechanism had three important consequences. First, languages were
invented that supported a variety of parameter-passing mechanisms.
Second, the foundations of structured programming were laid,
manifesting themselves in language support for the nest- ing of
subprograms and the development of theories regarding control
structures and the scope and visibility of declarations. Third, structured
design methods emerged, offering guidance to designers trying to build
large systems using sub- programs as basic physical building blocks.
Thus, it is not surprising, as Figure 2 shows, that the topology of late
second- and early third-generation languages is largely a variation on
the theme of earlier generations. This topology addresses
            Data
            Subprograms
   Figure 2 The Topology of Late Second- and Early Third-
                   Generation Programming Languages
some of the inadequacies of earlier languages, namely, the need to
have greater control over algorithmic abstractions, but it still fails to
address the problems of programming-in-the-large and data design.
The Topology of Late Third-Generation Programming Languages
Starting with FORTRAN II, and appearing in most late third-
generation program languages, another important structuring
mechanism evolved to address the growing issues of programming-in-
the-large. Larger programming projects meant larger development
teams, and thus the need to develop different parts of the same program
independently. The answer to this need was the separately compiled
module, which in its early conception was little more than an arbitrary
container for data and subprograms, as Figure 3 shows. Modules were
rarely recognized as an important abstraction mechanism; in practice
they were used simply to group subprograms that were most likely to
change together.
Most languages of this generation, while supporting some sort of
modular structure, had few rules that required semantic consistency
among module interfaces. A developer writing a subprogram for one
module might assume that it would be called with three different
parameters: a floating-point number, an array of ten elements, and an
integer representing a Boolean flag. In another module, a call to this
subprogram might incorrectly use actual parameters that violated these
assumptions: an integer, an array of five elements, and a negative
number. Similarly, one module might use a block of common data that
it assumed as its own, and another module might violate these
assumptions by directly manipulating this
          Modules
           Data
           Subprograms
Figure 3 The Topology of Late Third-Generation Programming
Languages
data. Unfortunately, because most of these languages had dismal
support for data abstraction and strong typing, such errors could be
detected only during execution of the program.
The Topology of Object-Based and Object- Oriented
Programming Languages
Data abstraction is important to mastering complexity. “The nature of
abstractions that may be achieved through the use of procedures is well
suited to the description of abstract operations, but is not particularly
well suited to the description of abstract objects. This is a serious
drawback, for in many applications, the complexity of the data objects
to be manipulated contributes substantially to the overall complexity of
the problem” . This realization had two important consequences. First,
data-driven design methods emerged, which pro- vided a disciplined
approach to the problems of doing data abstraction in algorithmically
oriented languages. Second, theories regarding the concept of a type
appeared, which eventually found their realization in languages such as
Pascal.
The natural conclusion of these ideas first appeared in the language
Simula and was improved upon, resulting in the development of several
languages such as Smalltalk, Object Pascal, C++, Ada, Eiffel, and Java.
For reasons that we will explain shortly, these languages are called
object-based or object-oriented. Figure 4 illustrates the topology of such
languages for small to moderate-sized applications.
  Figure 4 The Topology of Small to Moderate-Sized Applications
       Using Object-Based and Object-Oriented Programming
       Languages
The physical building block in such languages is the module, which
represents a logical collection of classes and objects instead of
subprograms, as in earlier languages. To state it another way, “If
procedures and functions are verbs and pieces of data are nouns, a
procedure-oriented program is organized around verbs while an
object-oriented program is organized around nouns”. For this reason,
the physical structure of a small to moderate-sized object-oriented
application appears as a graph, not as a tree, which is typical of
algorithmically oriented languages. Additionally, there is little or no
global data. Instead, data and operations are united in such a way that
the fundamental logical building blocks of our systems are no longer
algorithms, but instead are classes and objects.
By now we have progressed beyond programming-in-the-large and
must cope with programming-in-the-colossal. For very complex
systems, we find that classes, objects, and modules provide an
essential yet insufficient means of abstraction. Fortunately, the object
model scales up. In large systems, we find clusters of abstractions built
in layers on top of one another. At any given level of abstraction, we
find meaningful collections of objects that collaborate to achieve some
higher-level behavior. If we look inside any given cluster to view its
imple- mentation, we unveil yet another set of cooperative abstractions.
    This is exactly the organization of complexity described in Chapter 1;
    this topology is shown in Figure 5.
      Figure 5 The Topology of Large Applications Using Object-
                 Based    and   Object-Oriented    Programming
                 Languages
2   Foundations of the Object Model
    Structured design methods evolved to guide developers who were trying
    to build complex systems using algorithms as their fundamental
    building blocks. Simi- larly, object-oriented design methods have
    evolved to help developers exploit the expressive power of object-based
    and object-oriented programming languages, using the class and object
    as basic building blocks.
    Actually, the object model has been influenced by a number of factors,
    not just object-oriented programming. Indeed, as further discussed in
the sidebar, Founda- tions—The Object Model, the object model has
proven to be a unifying concept in computer science, applicable not
just to programming languages but also to the design of user interfaces,
databases, and even computer architectures. The reason for this
widespread appeal is simply that an object orientation helps us to cope
with the complexity inherent in many different kinds of systems.
Because the object model derives from so many disparate sources, it has
unfortu- nately been accompanied by a muddle of terminology. A
Smalltalk programmer uses methods, a C++ programmer uses virtual
member functions, and a CLOS programmer uses generic functions. An
Object Pascal programmer talks of a type coercion; an Ada programmer
calls the same thing a type conversion; a C# or Java programmer would
use a cast. To minimize the confusion, let’s define what is object-
oriented and what is not.
 Foundations—The Object Model
 As Yonezawa and Tokoro point out, “The term ‘object’ emerged
 almost independently in various fields in computer science, almost
 simultaneously in the early 1970s, to refer to notions that were
 different in their appear- ance, yet mutually related. All of these
 notions were invented to manage the complexity of software
 systems in such a way that objects represented components of a
 modularly decomposed system or modular units of knowl- edge
 representation” . Levy adds that the following events have contrib-
 uted to the evolution of object-oriented concepts:
   ■   Advances in computer architecture, including capability
       systems and hard- ware support for operating systems
       concepts
   ■   Advances in programming languages, as demonstrated in
       Simula, Smalltalk, CLU, and Ada
   ■   Advances in programming methodology, including
       modularization and infor- mation hiding
 We would add to this list three more contributions to the foundation
 of the object model:
   ■   Advances in database models
   ■   Research in artificial intelligence
    ■ Advances in philosophy and cognitive science
 The concept of an object had its beginnings in hardware over twenty
 years ago, starting with the invention of descriptor-based
 architectures and, later, capability-based architectures. These
 architectures represented a break from the classical von Neumann
 architectures and came about through attempts to close the gap
 between the high-level abstractions of programming languages and
 the low-level abstractions of the machine itself.According to its
 proponents, the advantages of such architec- tures are many: better
 error detection, improved execution efficiency, fewer instruction
 types, simpler compilation, and reduced storage requirements.
 Computers can also have an object-oriented architecture.
 Although database technology has evolved somewhat independently
 of software engineering, it has also contributed to the object model ,
 pri- marily through the ideas of the entity-relationship (ER) approach
 to data modeling. In the ER model, first proposed by Chen the world
 is modeled in terms of its entities, the attributes of these entities, and
 the rela- tionships among these entities.
Object-Oriented Programming
What, then, is object-oriented programming (OOP)? We define it as
follows:
   Object-oriented programming is a method of implementation in
   which programs are organized as cooperative collections of objects,
   each of which represents an instance of some class, and whose
   classes are all members of a hierarchy of classes united via
   inheritance relationships.
Object-Oriented Design
The emphasis in programming methods is primarily on the proper
and effective use of particular language mechanisms. By contrast,
design methods emphasize the proper and effective structuring of a
complex system. What, then, is object- oriented design (OOD)? We
suggest the following:
   Object-oriented design is a method of design encompassing the
   process of object- oriented decomposition and a notation for
   depicting both logical and physical as well as static and dynamic
   models of the system under design.
    There are two important parts to this definition: object-oriented design
    (1) leads to an object-oriented decomposition and (2) uses different
    notations to express different models of the logical (class and object
    structure) and physical (module and process architecture) design of a
    system, in addition to the static and dynamic aspects of the system.
    Object-Oriented Analysis
    The object model has influenced even earlier phases of the software
    development lifecycle.
       Object-oriented analysis is a method of analysis that examines
       requirements from the perspective of the classes and objects found
       in the vocabulary of the problem domain.
    How are OOA, OOD, and OOP related? Basically, the products of
    object-oriented analysis serve as the models from which we may start
    an object-oriented design; the products of object-oriented design can
    then be used as blueprints for com- pletely implementing a system
    using object-oriented programming methods.
3   Elements of the Object Model
    Jenkins and Glasgow observe that “most programmers work in one
    language and use only one programming style. They program in a
    paradigm enforced by the language they use. Frequently, they have not
    been exposed to alternate ways of thinking about a problem, and hence
    have difficulty in seeing the advantage of choosing a style more
    appropriate to the problem at hand”. Bobrow and Stefik define a
    programming style as “a way of organizing programs on the basis of
    some conceptual model of programming and an appropriate language
    to make programs written in the style clear”.They further suggest that
    there are five main kinds of programming styles, listed here with the
    kinds of abstractions they employ:
      3. Procedure-oriented    Algorithms
      4. Object-oriented       Classes and objects
      5. Logic-oriented        Goals, often expressed in a predicate
         calculus
      6. Rule-oriented         If–then rules
      7. Constraint-oriented   Invariant relationships
There is no single programming style that is best for all kinds of
applications. For example, rule-oriented programming would be best
suited for the design of a knowledge base, and procedure-oriented
programming would be best for the design of computation-intense
operations. From our experience, the object-oriented style is best suited
to the broadest set of applications; indeed, this programming paradigm
often serves as the architectural framework in which we employ other
paradigms.
Each of these styles of programming is based on its own conceptual
framework. Each requires a different mindset, a different way of
thinking about the problem. For all things object-oriented, the
conceptual framework is the object model. There are four major
elements of this model:
  1.   Abstraction
  2.   Encapsulation
  3.   Modularity
  4.   Hierarchy
By major, we mean that a model without any one of these elements is
not object- oriented.
There are three minor elements of the object model:
  1. Typing
  2. Concurrency
  3. Persistence
By minor, we mean that each of these elements is a useful, but not
essential, part of the object model.
Without this conceptual framework, you may be programming in a
language such as Smalltalk, Object Pascal, C++, Eiffel, or Ada, but
your design is going to smell like a FORTRAN, Pascal, or C
application. You will have missed out on or other- wise abused the
expressive power of the object-oriented language you are using for
implementation. More importantly, you are not likely to have mastered
the complexity of the problem at hand.