What is Object-Oriented Programming?

Any object-oriented program like a Java program, is a collection of interacting objects that models a collection of real-world objects. Think of the model that a kitchen designer might use to lay out your new kitchen. It will contain objects that represent the various kitchen appliances and cabinets. Each object in the model is a simplified version of the corresponding real object. For example, a rectangle might be used to represent the refrigerator.

Object-Oriented Programming - Kitchen analogy

A kitchen model is mostly static. It doesn’t change. Once put into place, its various objects just stand there in a certain relation to each other. By contrast, a computer program is dynamic. It changes. It does things and performs certain actions. The objects in a computer program communicate with each other, and they change over time. In this respect, the objects that make up our computer programs are very anthropomorphic, a big word that means “like people.” If we are eating together and I want you to pass me the salt, I say, “Please pass me the salt,” and you invariably comply. Similarly, when you (Student X) put your ATM card into an ATM machine, the ATM object asks the bank’s database object, “Give me Student X’s bank account object,” and the database invariably complies. If you tell the ATM you want to withdraw $100, it tells your bank account object to deduct $100 from your current balance. And so it goes. Both you and your bank account are changed objects as a result of the transaction.

What Is an Object?

So what is an object? Just as in the real world, an object is any thing whatsoever. An object can be a physical thing, such as a Car, or a mental thing, such as an Idea. It can be a natural thing, such as an Animal, or an artificial, human-made thing, such as an ATM. A program that manages an ATM would involve BankAccounts and Customer objects. A chess program would involve a Board object and ChessPiece objects.

Throughout this text, we will use the notation shown in figure below to depict objects and to illustrate object-oriented concepts. The notation is known as the Unified Modeling Language, or UML for short, and it is a standard in the object-oriented programming community. As the diagram shows, an object is represented by a rectangle whose label consists of the object’s (optional) id and its type. An object’s id is the name by which it is referred to in the computer program. In this case we show an ATM object whose id is not given and a ChessPiece object named pawn1. An object’s label is always underlined.

In UML, objects are represented by rectangles that are labeled with a two-part label of the form id:Type. The object's label is always underlined.

Attributes and Values

Just as with real objects, the objects in our programs have certain characteristic attributes. For example, an ATM object would have a current amount of cash that it could dispense. A ChessPiece object might have a pair of row and column attributes that specify its position on the chessboard. Note that an object’s attributes are themselves objects. The ATM’s cash attribute and the chess piece’s row and column attributes are Numbers.

Figure below shows two ATM objects and their respective attributes. As you can see, an object’s attributes are listed in a second partition of the UML diagram. Note that each attribute has a value. So the lobby:ATM has a $8650.00 in cash, while the drivethru:ATM has only $150.00 in cash.

A second partition of an object diagram is used to display the object's attributes and their values

We sometimes refer to the collection of an object’s attributes and values as its state. For example, the current state of the lobby:ATM is $8650.00 in cash. Of course, this is a gross simplification of an ATM’s state, which would also include many other attributes. But it illustrates the point for you.

Actions and Messages

In addition to their attributes, objects also have characteristic actions or behaviors. As we have already said, objects in programs are dynamic. They do things or have things done to them. In fact, programming in Java is largely a matter of getting objects to perform certain actions for us. For example, in a chess program the ChessPieces have the ability to moveTo() a new position on the chessboard. Similarly, when a customer pushes the “Current Balance” button on an ATM machine, this is telling the ATM to report() the customer’s current bank balance. (Note how we use parentheses to distinguish actions from objects and attributes.)

The actions that are associated with an object can be used to send messages to the objects and to retrieve information from objects. A message is the passing of information or data from one object to another. Figure below illustrates how this works. In UML, messages are represented by arrows. In this example, we are telling pawn1:ChessPiece to moveTo(3,4). The numbers 3 and 4 in this case are arguments that tell the pawn what square to move to. (A chess board has eight rows and eight columns, and each square is identified by its row and column coordinates.) In general, an argument is a data value that specializes the content of a message in some way. In this example we are telling the pawn to move forward by one row. If we wanted the pawn to move forward by two rows, we would send the message moveTo(4,4).

Messages in UML are represented by labeled arrows. In this example, we are telling a pawn to move from its current position to row 3 column 4.

Messages in UML are represented by labeled arrows. In this example, we are telling a pawn to move from its current position to row 3 column 4.

The diagram in the figure below depicts a sequence of messages representing an idealized ATM transaction. First, an ATM customer asks the ATM machine to report his current balance. The ATM machine in turn asks the customer’s bank account to report the customer’s balance. The ATM receives the value $528.52 from the bank account and passes it along to the customer. In this case, the message does not involve an argument. But it does involve a result. A result is information or data that is returned to the object that sent the message.

This UML diagram illustrates an ATM transaction in which a customer asks the ATM machine for his current balance. The ATM gets this information from an object representing the customer's bank account and passes it to the customer.

This UML diagram illustrates an ATM transaction in which a customer asks the ATM machine for his current balance. The ATM gets this information from an object representing the customer’s bank account and passes it to the customer.

Obviously, in order to respond to a message, an object has to know how to perform the action that is requested. The pawn has to know how to move to a designated square. The ATM has to know how to find out the customer’s current balance. Indeed, an object can only respond to messages that are associated with its characteristic actions and behaviors. You can’t tell an ATM to move forward two squares. And you can’t ask a chess piece to tell you your current bank balance.

Responding to a message or performing an action sometimes causes a change in an object’s state. For example, after performing moveTo(3,4), the pawn will be on a different square. Its position will have changed. On the other hand, some messages (or actions) leave the object’s state unchanged. Reporting the customer’s bank account balance doesn’t change the balance.

What Is a Class?

A class is a template for an object. A class encapsulates the attributes and actions that characterize a certain type of object. In an object-oriented program, classes serve as blueprints or templates for the objects that the program uses. We say that an object is an instance of a class. A good analogy here is to think of a class as a cookie cutter and its objects, or instances, as individual cookies. Just as we use the cookie cutter to stamp out cookies of a certain type, in an object-oriented program, we use a definition of a class to create objects of a certain type.

Writing an object-oriented program is largely a matter of designing classes and writing definitions for them in Java. Designing a class is a matter of specifying all of the attributes and behaviors that are characteristic of that type of object.

For example, suppose we are writing a drawing program. One type of object we would need for our program is a rectangle. A Rectangle object has two fundamental attributes, a length and a width. Given these attributes, we can define characteristic rectangle actions, such as the ability to calculate its area and the ability to draw itself. Identifying an object’s attributes and actions is the kind of design activity that goes into developing an object-oriented program.

Figure below shows a UML diagram of our Rectangle class. Like the symbol for an object, a UML class symbol has up to three partitions. Unlike the UML object symbol, the label for a UML class only gives the class’s name and is not underlined. The second partition lists the class’s attributes, and the third partition lists the class’s actions. Our rectangle has four attributes. The first two, x and y, determine a rectangle’s position on a two-dimensional graph. The second two, length and width, determine a rectangle’s dimensions. Note that the attributes have no values. This is because the class represents a general type of rectangle. It specifies what all rectangles have in common, without representing any particular rectangle. Like a cookie cutter for a cookie, a class gives the general shape of an object. The content is not included.

A UML diagram of the Rectangle class

Variables and Methods

Up to this point we have been using the terms attribute and action to describe an object’s features. We will continue to use this terminology when talking in general about objects or when talking about an object or class represented by a UML diagram.

However, when talking about a programming language, the more common way to describe an object’s features is to talk about its variables and methods. A variable, which corresponds to an attribute, is a named memory location that can store a certain type of value. You can think of a variable as a special container that can only hold objects of a certain type. For example, as the figure above shows, Rectangle’s length and width are variables that can store a certain type of numeric value known as an int. An int value is a whole number, such as 76 or -5.

A method, which corresponds to an action or a behavior, is a named chunk of code that can be called upon, or invoked, to perform a certain predefined set of actions. For example, in our Rectangle object, the calculateArea() method can be called upon to calculate the rectangle’s area. It would do this, of course, by multiplying the rectangle’s length by its width. Similarly, the draw() method can be invoked to draw a picture of the rectangle. It would take the actions necessary to draw a rectangle on the console.

Instance (Object) versus Class Variables and Methods

Variables and methods can be associated either with objects or their classes. An instance variable (or instance method) is a variable (or method) that belongs to an object. By contrast, a class variable (or class method) is a variable (or method) that is associated with the class itself. An example will help make this distinction clear.

An instance variable will have different values for different instances. For example, individual Rectangles will have different values for their length, width, x, and y variables. So these are examples of instance variables. The calculateArea() method is an example of an instance method because it uses the instance’s current length and width values in its calculation. Similarly, the draw() method is an instance method because it uses the object’s length and width to draw the object’s shape.

An example of a class variable would be a variable in the Rectangle class that is used to keep track of how many individual Rectangles have been created. (Our drawing program might need this information to help manage its memory resources.) Suppose we name this variable nRectangles, and suppose we add 1 to it each time a new Rectangle instance is created.

An example of a method that is associated with a class is a special method known as a constructor. This is a method used to create an object. It is used to create an instance of a class. Calling a constructor to create an object is like pressing the cookie cutter into the cookie dough: the result is an individual cookie (object).

Figure below illustrates these concepts. Note that class variables are underlined in the UML diagram. We have modified the Rectangle class to include its constructor method, which is named Rectangle(). It takes four arguments, representing the values that we want to give as the rectangle’s x, y, length, and width respectively. The Rectangle class’s nRectangles variable has a value of 2, representing that two Rectangle instances have been created. These are shown as members of the Rectangle class.

The Rectangle class and two of its instances. The class variable, nRectangles, is underlined to distinguish it from length and width, the instance variables.

The Rectangle class and two of its instances. The class variable, nRectangles, is underlined to distinguish it from length and width, the instance variable.

It won’t be obvious to you at this point, but nRectangles is a value that has to be associated with the Rectangle class, not with its instances. To see this, let’s imagine what happens when a new Rectangle instance is created. Figure below illustrates the process. When the Rectangle() constructor is invoked, its arguments (100, 50, 25, 10) are used by the Rectangle class to create a Rectangle object located at x=100, y=50 and with a length of 25 and width of 10. The constructor method also increases the value of nRectangles by 1 as a way of keeping count of how many objects it has created.

Constructing a Rectangle instance.

Class Hierarchy and Inheritance

How are classes related to each other? In Java, and in any other object-oriented language, classes are organized in a class hierarchy. A class hierarchy is like an upside-down tree. At the very top of the hierarchy is the most general class. In Java, the most general class is the Object class. The classes below Object in the hierarchy are known as its subclasses. Since all of the objects we use in our programs belong to some class or other, this is like saying that all objects are Objects.

Figure below illustrates the concept of a class hierarchy using the classes that we have described in this section. As you can see, the Object class occurs at the top of the hierarchy. It is the most general class. It has features that are common to all Java objects. As you move down the hierarchy, the classes become more and more specialized. A Rectangle is an Object, but it contains attributes (length and width) that are common to all rectangles but not to other objects in the hierarchy. For example, an ATM object does not necessarily have a length and a width. Note that we have added a Square class to the hierarchy. A Square is a special type of Rectangle, one whose length equals its width.

A hierarchy of Java classes.

A hierarchy of Java classes.

Superclass and subclass

To introduce some important terminology associated with this kind of hierarchy, we say that the Rectangle class is a subclass of the Object class. The Square class is a subclass of both Rectangle and Object. Classes that occur above a given class in the hierarchy are said to be its superclasses. Thus the Rectangle class is a superclass of the Square class. The Object class is also a superclass of Square. In general, we say that a subclass extends a superclass, meaning that it adds additional elements (attributes and/or methods) to those contained in its superclasses. We saw this in the case of the Square class. It adds the feature that its length and width are always equal.

Another important concept associated with a class hierarchy is the notion of class inheritance, whereby a subclass inherits elements (attributes and/or methods) from its superclasses. To take an example from the natural world, think of the sort of inheritance that occurs between a horse and a mammal. A horse is a mammal. So horses inherit the characteristic of being warm-blooded by virtue of also being mammals. (This is different from the kind of individual inheritance whereby you inherit your mother’s blue eyes and your father’s black hair.)

Class inheritance

To illustrate how inheritance works, let’s go back to our chess program. There are several different types of ChessPieces. There are Pawns, and Knights, and Queens and Kings. Figure below illustrates the chess piece hierarchy. A pair of attributes that all chess pieces have in common is their row and column position on the chessboard. Because all chess pieces have these attributes in common, they are located at the top of the ChessPiece hierarchy and inherited by all ChessPiece subclasses. Of course, the row and column attributes are given different values in each ChessPiece object.\

The ChessPiece hierarchy in OOO

Class hierarchy of the ChessPiece

One of the actions that all chess pieces have in common is that they can moveTo() a given square on the chessboard. But different types of chess pieces have different ways of moving. For example, a Bishop can only move along the diagonals on the chessboard, whereas a Rook can only move along a row or column on the chessboard. So, clearly, we can’t describe a moveTo() method that will work for all ChessPieces. This is why we put the moveTo() method in all of the ChessPiece subclasses. The ChessPiece class also has a moveTo() method, but note that its name is italicized. This indicates that it cannot be completely defined at that level.

Finally, note that in chess, the king has certain special attributes and actions. Thus only the king can be put in check. This means that the king is under attack and in danger of being captured, thereby ending the game. Similarly, only the king has the ability to castle. This is a special move that a king can make together with one of its rooks under certain conditions. Thus, the reason we show the inCheck attribute and castle() action in the King class is because these are characteristics that are particular to Kings.

In this way, a class hierarchy represents a specialization of classes as you move from top to bottom. The most general class, ChessPiece, is at the top of the hierarchy. Its attributes and methods are passed on to (inherited by) its subclasses. However, in addition to the attributes and methods they inherit from their superclasses, the subclasses define their own special attributes and methods. Each of the subclasses, Pawn, Bishop, and so on, represents some kind of specialization of the superclass. In this example, each of the subclasses has its own distinctive way of moving. And the King subclass has unique attributes and actions, inCheck and castle().

Principles of Object-Oriented Design

As we have discussed, an object-oriented program is composed of many objects communicating with each other. The process of designing an object-oriented program to solve some problem or other involves several important principles:

Divide-and-Conquer Principle. Generally, the first step in designing a program is to divide the overall problem into a number of objects that will interact with each other to solve the problem. Thus, an object-oriented program employs a division of labor much like the one we apply in organizing many of our real-world tasks. This divide-and-conquer approach is an important problem-solving strategy.

Encapsulation Principle. Once the objects are identified, the next step involves deciding, for each object, what attributes it has and what actions it will take. The goal here is to encapsulate within each object the expertise needed to carry out its role in the program. Each object is a self-contained module with a clear responsibility and the tools (attributes and actions) necessary to carry out its role. Just as a dentist encapsulates the expertise needed to diagnose and treat a toothache, a well-designed object contains the information and methods needed to perform its role.

Interface Principle. In order for objects to work cooperatively and efficiently, we have to clarify exactly how they are to interact, or interface, with one another. An object’s interface should be designed to limit the way the object can be used by other objects. Think of how the different interfaces presented by a digital watch and an analog watch determine how the watches are used. In a digital watch, time is displayed in discrete units, and buttons are used to set the time in hours, minutes, and seconds. In an analog watch, the time is displayed by hands on a clock face, and time is set, less precisely, by turning a small wheel.

Information-Hiding Principle. In order to enable objects to work together cooperatively, certain details of their individual design and performance should be hidden from other objects. To use the watch analogy again, in order to use a watch we needn’t know how its time-keeping mechanism works. That level of detail is hidden from us. Hiding such implementation details protects the watch’s mechanism but does not limit its usefulness.

Generality Principle. To make objects as generally useful as possible, we design them not for a particular task but rather for a particular kind of task. This principle underlies the use of software libraries. As we will see, Java comes with an extensive library of classes that specialize in performing certain kinds of input and output operations. For example, rather than having to write our own method to print a message on the console, we can use a library object to handle our printing tasks.

Extensibility Principle. One of the strengths of the object-oriented approach is the ability to extend an object’s behavior to handle new tasks. This also has its analog in the everyday world. If a company needs sales agents to specialize in hardware orders, it would be more economical to extend the skills of its current sales agents instead of training a novice from scratch. In the same way, in the object-oriented approach, an object whose role is to input data might be specialized to input numeric data.

Abstraction Principle. Abstraction is the ability to focus on the important features of an object when trying to work with large amounts of information. For example, if we are trying to design a floor plan for a kitchen, we can focus on the shapes and relative sizes of the appliances and ignore attributes such as color, style, and manufacturer. The objects we design in our Java programs will be abstractions in this sense because they ignore many of the attributes that characterize the real objects and focus only on those attributes that are essential for solving a particular problem.

License



Speak Your Mind

-->