The Object-Oriented Philosophy

Steven J Zeil

Last modified: August 20, 2013
Contents:

If OO analysis and design is about any one thing, it’s about how to find and recognize good ADTs.

Earlier, we looked at functions as a basis for design. We saw that, although certainly workable as a low-level design technique, designing based on functionality does not naturally lead to good ADT organization.

1 The Object-Oriented Philosophy

As we have noted, OO programming languages had their roots in simulation.

The first proponents of OO looked back to simulation, one of the early success stories in programming and design. Many early simulation programmers were able to construct programs that were organized in a way that made them easy to modify and maintain.

In part this was because Simula and other simulation programming languages offered features that supported ADTs as modular building blocks – but so did many other programming languages. Beyond the question of what the language supported, there was the issue of how those simulation programmers organized their programs in the first place. They were, in a very literal sense, keeping it real.

This, it was thought, was because the focus on modeling the real world, in a language that created a module for each kind of real-world object, led to programs that felt “natural” and easily understood by anyone who understood the part of the real world that was being simulated.

1.1 Program = Simulation

The Object-Oriented Philosophy

  • Every program is really a simulation.
  • The quality of a program’s design is proportional to the faithfulness with which the structures and interactions in the program mirror those in the real world.

According to this philosophy, a program to manage book handling in a library is really a simulation of what the librarians would have done prior to automation. A program to compute a company payroll is a simulation of what the accounting clerks would have done. A program to compute student grades at the end of a semester is a simulation of what a teacher would have done manually.

Now, sometimes the worlds being simulated may be artificial or imaginary (e.g., chess and other games, fractal mathematics) but, as long as they are well understood, that really doesn’t matter. You may be able to come up with exceptions to the “every program is a simulation” rule,1 but the very fact that you have to think for a while to do so is a significant sign that this claim is plausible,

If you buy the first part of this philosophy, then the second part becomes really interesting. Ever listen to another programmer explain a design and wonder how the heck that was going to solve the problem at hand? Ever notice how programmers love to make up new terms for things in their code, often in defiance of the normal English-language meaning of the word? Or, even worse, ever read code where the variables had names like info or data or value or the functions had names like processData? Does anyone think names like those {\em really} have any informational content?

The OO philosophy suggests that the things manipulated by the program should correspond to things in the real world. They should carry the same names as those things carry in the real world. And they should interact in ways like those objects n the real world.


Design from the World

In our [earlier example]{doc:functionalDesign), we considered a function-based approach to design, coming up with subsystems like RecordStorage, CheckInOut, AccountMgmt, and InventoryMgmt.

In the OO approach to our earlier library design, we might never arrive at those. Instead, we would draw upon our knowledge of the world of libraries and say that this world is populated by Books, CardCatalogs, Librarys, LibraryBranches, Patrons, etc., and these would become our initial set of ADTs, our modules for the system design. If our personal knowledge of the world of libraries is not quite up to snuff, we can ask the domain experts, the librarians and staff and patrons of the library.


Real-World Relationships


Organizing the World

OO designers would start by organizing these things into ADTs, e.g.:

 

(These are examples of classes as diagrammed in UML. We introduced this notation earlier.)


Simulate the World’s Actions

Only then would OO designers consider the specific steps required to add a book to inventory:

“update the electronic card catalog so that the book can be found, and record that the book is present in the inventory of a particular branch”


Simulate the World’s Actions

function Librarian::acquisition (Book book) 
{ 
  BranchLibrary branch = this.assignment;
  Catalog catalog = mainLibrary.catalog;
  catalog.add (book, branch);
  branch.addToInventiory (book);
}

function Catalog::add (Book book)
{
  authorIndex.add (book);
  titleIndex.add (book);
  subjectIndex.add (book);
}      


OO Approach - Observations

Technically, does the same thing as the earlier design,but

What’s the advantage to this?

“OK, so the LB database…”

“The what?”

“The LB database - that’s where we store the information that used to be in the card catalog. OK, the LB database has to store info about more than just books. You have magazines, CDs, DVDs, etc. So the LB database can contain any kind of shelvable item.”

“Shelvable item? You mean any kind of publication, right?”

“Uh, yeah. We decided to call them shelvable items because they represent anything you can put on a shelf. Anyway, the LB database can…”

Grady Booch suggested the “principle of least surprise” as a guide to designing ADT interfaces. The idea is that, given that we all share a certain common understanding of how things are supposed to work, any surprises we encounter when reading someone’s design are invariably unpleasant ones, representing a place where the design deviates from our expectation of how it would be most likely to work. Each such surprise is something that we are going to have to remember later, whenever we try to work with that particular designed component. If the choice of ADTs is “natural” to the application domain, if the names are natural, if the interactions (function calls) between them are natural, we have fewer surprises to cope with and fewer diddly little details likely to go wrong.

Hopefully, then it’s clear how an OO approach can have a big impact on the design of our programs. Closely related to OOD is OOA. If “design” is all about figuring out how to make a program do what we want, “analysis” is about first figuring out what we want it to do. But programs don’t run in isolation. They interact with objects in the surrounding world. So it should not come as a shock that thinking about the world as a collection of interacting objects helps here too. If real-world librarians check out books for library patrons, then isn’t it natural to assume that an automated librarian would check out books for library patrons?

1.2 Simulation == Modeling


OO Analysis & Design


Models

We can rephrase that as

Note our approach in the earlier library examples: we built a model of the library world, and took for granted that this was the basis for design of library code.


Steps in Modeling

Both of these steps are often driven by scenarios.

2 Putting the “Programming” in OOP


OOP in Programming Language History

Language Concepts Examples Design Concepts
Statements Stepwise Refinement
Functions FORTRAN (1957), COBOL, ALGOL, Basic (1963), C (1969), Pascal (1972) Top-Down Design
Encapsulated modules, classes Modula, Modula 2 (1970), Ada (1983) Information hiding, ADTs
Inheritance, subtyping, dynamic binding (OOP) Smalltalk (1980), C++ (1985), Java (1995) Object-Oriented A&D

So, if the point of OOA and OOD is to come up with good ADTs, why do we need OOP? In fact, many OODs lead to programs that could be implemented very nicely in a pre-OO programming language that had good support for ADTs. But certain patterns of behavior crop up again and again in simulations, patterns that could not be easily supported in those earlier languages. The languages that we call object-oriented evolved to support these behaviors. This does not replace support for ADTs - all OOPLs start with good support for ADTs. But then they add to it the capability for class- or object-variant behaviors.

2.1 What is an Object?

Maybe you thought I was never going to get around to this?

An object is characterized by

2.1.1 Identity

Identity is the property of an object that distinguishes it from all others. We commonly denote identity by

2.1.2 State

The state of an object consists of the properties of the object, and the current values of those properties.

For example, given this list of properties:

 struct Book {
    string title;
    Author author;
    ISBN isbn;
    int edition;
    int year;
    Publisher publisher;
 };

we might describe the state of a particular book as

 Book cs330Text = {
    "Object Oriented Design & Patterns", horstmann,
    "0-471-74487-5", 2, 2006,
    wileyBooks};

2.1.3 Behavior

Behavior is how an object acts and reacts to operations on it, in terms of

OK, identity, state, and behavior are nice ideas. But what’s it really add up to? How do you know if you have a good object?

Personally, I’m rather fond of the “kick it” test. If you can kick it, it’s an object. Returning again to our library example, Books, CardCatalogs, Librarys, LibraryBranches, Patrons are all physical tangible objects. If I came up to one, I could give it a kick. (Some of them might kick back!) So I think I can accept all of these as classes of objects.

What about RecordStorage, CheckInOut, AccountMgmt, and InventoryMgmt. Have you ever walked down a hall and tripped over an InventoryMgmt? Could you kick/touch/hold a CheckInOut? That’s a pretty good clue that these are not objects.

Object (and class) names are invariably noun phrases. A good rule of thumb is that tangible objects in the real world make good objects in the simulated world. This includes people. However, not all simulated objects need to be tangible. Events are often objects. Roles played by people in a system are often objects.

Some things that are terrible choices for objects early in the system development become acceptable later on. For example, is RecordStorage an object?

But later on, when we are deep in design, if we make a design decision to unite the card catalog and circulation and inventory records into a database, calling that a RecordStorage object might not be quite so awful (though I’d still prefer a more descriptive name). That’s because, although this thing does not exist in the old unautomated world, it will exist in the new world that includes our automated system.

2.2 Messages & Methods

In OOP, behavior is often described in terms of messages and methods.

A message to an object is a request for service.

A method is the internal means by which the object responds to that request.


Differing Behavior

Different objects may respond to the same message via different methods.

Example: suppose I send a message “send flowers to my grandmother” to …

  • a florist
first prev1 of 8next last

In using objects, we must know what messages they will successfully respond to, not necessarily the method of the response. But how can we even know whether a group of objects respond to some common message? All OOPLs provide some way to organize objects according to the messages they accept. Most common is to group them by class.

2.3 What is a Class?

A class is a named collection of potential objects.

In the languages we will study,

By now you might start to wonder if objects and classes are really all that new, or if I’m just playing terminology games with you. In fact, all the terms I have introduced in this lesson have direct correspondences to more traditional programming terms:


Are Objects and Classes New?

OOPL Traditional PL
object variable, constant
identity label, name, address
state value
class type (almost)
message function decl
method function body
passing a message function call

So all the new vocabulary we’ve been introduced to has existing equivalents in the traditional programming world.

One advantage to the new vocabulary is that it helps get you in the mindset of thinking of the program as a simulation of actual objects.


Classes versus Types

Although “class” and “type” mean nearly the same thing, they do carry a slightly different idiomatic meaning.

Although you can interchange “type” and “class” in many statements, the use of the word “type” carries with it an implication that only one is involved.

How is it possible for one object to be a member of multiple classes? It happens in the real world all the time that we divide things into multiple levels of ever-finer classes: This occurs because classes can be related via “inheritance”.


Instances of Multiple Types

If you have ever played the game “20 Questions”, you may be familiar with the stereotypical opening questions:

“Is it an animal?”

If the answer is no, this is followed with “Is it a vegetable?” (meaning any plant at all). If the answer to that is false, the object is known to be a “mineral” because only tangible objects are considered fair game in most versions of 20 Questions.

If the answer to the animal question were “yes”, however, this is generally followed by questions regarding its diet: “Is it a carnivore?”, “Is it an herbivore?” and so on. An answer of “yes” to the herbivore question might be followed by “Does it eat grass?” (ruminants).


Inheritance Example

 

The diagram here shows that we are progressively restricting ourselves to more specialized classes. Now, clearly Bessie the cow (a specific object) is a member fo the class Cow but that is not all. She is simultaneously a member of the class Ruminant and of the classes Herbivore, Animal, and of the class of valid 20 Questions objects.

This ability to model some classes ans specializations of others is, together with the ability to implement variant behaviors in response to a common message, precisely what traditional PLs were unable to support but that OOPLs were designed to allow.

How do we know if a group of objects will respond to a message? If they are all members, at some level, of a class that supports that message. (Later we will look at an additional mechanism often employed for this purpose, “subtyping”.)

How does an object determine what method to use in response to a message? It uses the method associated with the most specific (specialized) class to which it belongs. We will later see that this rule is referred to as “dynamic binding”.


What makes a PL an OOPL?

We’ll learn what these more specialized terms mean as the semester progresses.


1: Designing and writing compilers might be an example. The thing that compilers do is simply not something that anyone does manually in the real world, and, if they did, the techniques used in a compiler are unlikely to be anything like what, say, an Assembler-language programmer would use in writing Assembler code based upon a higher-level pseudo-code design.

2: Emphasis on the word “things”!