Introducing OOP
Procedural (aka structured) programming works well when applied to linear problems like processing the monthly payroll or sending out a set of utility bills. You feed a list of employees and their hours into one end of a program and get a pile of paychecks out the other. You organize your programs as assembly lines which processes data. This works very well.
But how do you apply the assembly line model to your Web browser? Where is the beginning? Where's the end?
When it comes to interactive software, a better method of organization is needed, and that's where OOP (Object-Oriented Programming) comes in. In an object-oriented program, the basic "building-block" is not the function, but the object. OOP programs look more like communities than assembly lines. Each object has its own attributes and behavior, and your program "runs" as the objects interact with one another.
What are Objects?
Objects are simply variables of programmer-defined types. Objects can represent real things, like employees or automobile parts or apartment buildings; objects can also represent more abstract concepts, such as relationships, times, numbers, or black holes.
Regardless of what kind of objects you use, you'll want to be able to recognize an object when you meet one. That's easy to do, because all objects have three properties:
- Identity: who the object is
- State: the characteristics of the object
- Behavior: what the object can do
Object Identity
In C and C++, we often use the term object to refer to a "bucket in memory" that contains data values of a particular type. In this sense, regular variables are objects:
int little = -4;
int big = 1795321;
int& tiny = little;
The names little and big are different areas of memory storing integer values. Changing little, it won't affect the variable big; the variables have different identities. But, tiny is not another variable but a different name; tiny and little have the same identity; they are different names for the same object.
State and Behavior
The second property is object state. The state of an object includes all the information about the object at a particular time. Take a look at the "Back" button on your Web browser. The UML (Unified Modeling Language) object diagram to the right displays a Button object named backButton. A Button object might have attributes like:
- Position: where the button is located on the screen
- Size: the button's width and height
- Caption: any text, such as the word "Back," that the button displays
- Image: any icon or image that is displayed on the button's surface
- Clicked: whether or not the button is currently selected (pressed)
The state of the object is represented by the values of those attributes. The backButton may display an arrow image but no text, and, if you click on the button with your mouse, its clicked state may change from false to true.
Object Behavior
The third property shared by all objects, and what differentiates them from structure types, is behavior. The behavior of an object consists of the messages that it responds to.
In the UML diagram on the right, the behavior is implemented by the member functions appearing in the bottom portion of the box. You ask the backButton object to change its size, for instance, by sending it a message with the desired size like this:
backButton.setSize(300, 100);
Since the backButton object has a setSize() member function, (as shown in the UML diagram), it does as you've asked.
What are Classes?
A class represents the definition—the blueprint if you like—used to create objects. Objects are simply variables, created (or instantiated) from this blueprint.
Like a structure, a class describes the attributes of an object: the kinds of data it stores internally. To design a Car class, you specify the physical characteristics that car shares: its serial number, body type, color, type of interior, engine size, etc.
Such attributes are stored as the object's data-members ( instance variables in Java).
A class also describes and implements the behaviors of its objects: the kinds of operations that each object in the class can perform. When you define a class, you need to specify what the object can do, providing an explicit list of its possible behaviors.
These are specified as embedded functions, called member functions in C++; in Java these are called methods. Member functions contain the interface (as prototypes in the class definition), and the instructions (appearing in the implementation) that tells each particular object how to complete a particular task.
To ask an object to perform some action, invoke or call one of its member functions. To emphasize the fact that objects represent fairly self-contained, autonomous units, the process of invoking a method is often called sending a message to the object.
What is Encapsulation?
With structures, the functions that make up the program, and the data the functions operate on, are separate. In an object-oriented program, they are combined. This process of wrapping up procedures and data together is called encapsulation.
Encapsulation is used to enforce the principle of data hiding, and, to allow your objects to enforce their own invariants, as we saw in the last chapter. With encapsulation, the data members defined inside a class are accessible to all the member functions defined inside the same class, but cannot be accessed by methods outside that class.
As you saw with the Time structure, making the data publicly accessible risks accidental data corruption as a result of a bug in someone else's code. The struct version of the Time type provides no abstraction and no encapsulation.
The Time interface is its implementation–the operations that clients can perform on the Time object are simply direct manipulation of its data. Changing the implementation thus changes the interface, which is why changing the data members breaks existing code.
Encapsulation in the "Real" World
You might find encapsulation a strange idea; why make it harder for your programs to access their data? In fact, out in the real world, all of us are familiar with the ideas of encapsulation. Let me give you a few examples.
- Today's automobiles are more complex than Henry Ford's original car. Despite this, driving the latest Tesla is similar to, if not simpler than, driving a Model-T. Why, because, as cars got more complex, that complexity was hidden behind a simplerinterface: the ignition (key), steering wheel, accelerator and brakes. These internal changes don't require drivers to take a new "how to drive" course. The implementation details are encapsulated.
- Your computer is another marvel of complexity. Unless you are a hardware tech, though, you never open up the system unit and try to operate it by shorting the circuits with a paper-clip. Instead, you use the interface—the mouse, and keyboard— to control the complex working parts that it contains.
- Finally, think about your TV. It's probably at least as complex as your car or your computer, but you don't need a license or a degree to operate one. Thanks to the magic of encapsulation, exemplified by the remote control, every child in the country can harness that power, although if you are a parent or grandparent, you might wish that were not true.
Just as with automobiles, computers and TVs, when it comes to programming, instead of making things more difficult, encapsulation makes objects safer and easier to use.
Encapsulation is one of the pillars underlying OOP or Object-Oriented Programming. We'll cover the other two, inheritance and polymorphism, next week.