- Special Edition Using Java, 2nd Edition -

Chapter 6

Object Oriented Programming


by Joe Weber

By now, as a programmer you have no doubt heard of a marvelous term called OOP, or object-oriented programming. OOP is truly the hottest method of software development today. It isn’t a totally new concept, but it has been a long time in coming to the masses. While Java doesn’t impose OOP programming like some languages (such as SmallTalk), it does embrace it and allow you to dance with the technology seamlessly.

Object Oriented Programming: A New Way of Thinking

Object-oriented programming is at once a completely new way of programming, and at the same time, contrary to the belief of some ,it is much the same as structured programming. Once you learn and embrace the new terms and concepts associated with object programming, the switch can be so easy you may not even notice you are doing it. You see, the goal of OOP is to provide you, the programmer, with a few new ways to actually write code, and several new ways to think about programming.

A Short History on Programming

Very early on, programming was extremely procedural. If you have ever tried to give another person directions on how to tie their shoes, you will find that it is very difficult. Especially if they have never (or acts as if they have never) seen shoelaces before. It is necessary to give very precise directions step by step by step. If you can grasp the number of instructions you would need to give to tell a person to tie their shoes like this, you may be able to grasp what this type of programming was like. It was necessary to give directions such as “Push the contents of register 1 onto the stack,” “Take the contents of the accumulator and place them in register one,” and so on.

Procedural Languages

Very soon programmers saw the need for more stylized procedural languages. These procedural languages placed code into blocks called procedures or functions. The goal of these blocks was to create black boxes which completed one task or another. Idealists believed that you could always write these functions without modifying external data, so in essence, the ideal was not only to build a black box, but when you were done testing it, weld the box shut.

One of the difficult problems with this method is to write all functions in a way so that they actually do not modify data outside their boundary. Frequently, this turns out to be too difficult of a constraint. So, as functions began changing data outside their scope (in C this is done by passing a pointer), a problem called coupling began to surface. Because the functions were now changing data outside of their scope, testing became more and more difficult.

As large programs were developed, the problem of coupling reared its ugly head. Testing these programs begot a whole subindustry, and software managers lost most of their hair, or if they were lucky enough to keep it, never cut it.

Structured Development

The next solution was to try structured development. Using structured development, programmers were expected to plan 100 percent of their program before ever writing a line of code. The heavy pre-code work proved to be effective in some cases, but limiting for most. This was in part because the emphasis became on good documentation and not necessarily great design.

When programmers were pushed to predesign all of their code before actually writing any code, a bad thing happened. Programming became institutionalized. Good programs tended to be as much experimentation as real development. Structured development pulled at this portion of the development cycle.

Ahh...Object Oriented Programming

Finally, along came Object Oriented Programming. The resulting programming technique at once goes back to procedural development by emphasizing black boxes, embracing structured development (and actually pushes it further), and most importantly encouraging creative programming design.

Under an OOP paradigm, it is objects which are represented in a system, not just their acquainted data structures. Objects aren’t just numbers, like integers and characters; they are also the methods which relate and manipulate the numbers. In OOP programming, rather than passing data around a system openly, messages are passed to and from objects. Rather than taking data and pushing it through a function, a message is passed to an object telling it to perform its task.

Objects are robust packages of both data and methods which are replicateable, and adjustable without damaging the predefined code. Instead of being trapped under innumerable potential additional uses, a method’s purpose is easily definable, as is the data upon which it will work.

Objects can be expanded, and by deriving new objects from existing ones, code time is greatly reduced. Equally important (if not more so) debug time is greatly reduced by localizing bugs.

A Lesson in Objects

As you work, you are familiar with objects all the time: calculators, phones, computers, fax machines, and stereos are all examples of objects in the real world. When you deal with these objects, you don’t separate the object from its quantities and methods. For example, when you turn on your stereo, you don’t think about the quantities (such as the station number) from the methods (such as turning the dial or making sound). You simply turn it on, select a station, and sit back to listen to the music.

By using object oriented programming, you can approach the same simplicity of use. As a structured programmer, you are used to creating data structures to hold data, and to defining methods and functions to manipulate this data. Objects, however, take and combine the data with the code. The synergistic relationship that comes out is one object that knows everything necessary to exist and work.

Take a look at an example using your car. When you describe a car, there are a number of important physical factors: the number of people a car can hold, the speed the car is going, the amount of horse power the engine has, the drag coefficient, and so on. In addition, the car has several functional definitions: it accelerates, decelerates, turns, and parks. Neither the physical nor the functional definitions alone embody the definition of your car—it is necessary to define them both.

Traditional Program Design

In a traditional program, you might define a data structure called MyCarData which might look like this:

public class MyCarData {
int weight;
float speed;
int hp;
double dragCoef;
}

Then you would create a set of methods to deal with the data:

public class RunCar {
public void speedUp(MyCarData m){
...
}
public void slowDown(MyCarData m){
...
}
public void stop(MyCarData m){
...
}
}

The OOP Way

In OOP programming, the methods for the car to run and the actual running of the car would be combined into one object:

public class MyCar{
int weight;
float speed;
int hp;
double dragCoef;
public void speedUp(){
speed += hp/weight;
}
public void slowDown(){
speed -= speed * dragCoef;
}
public void stop(){
speed=0;
}
}

Within each of the new methods, there is no need to either reference the variables using dot notation (such as m.speed) or pass in a reference to variables (such as (MyCarData m)). The methods implicitly know about the variables.

Extending Objects Through Inheritance

The next step in developing objects is to create multiple objects based on one “super” object. Let’s return to the car example. A Saturn SL2 is a car, and yet certainly it has several attributes that not all cars have. When building a car, manufacturers don’t typically start from scratch. They know their cars are going to need several things: tires, doors, steering wheels, and more. Frequently, the same parts can be used between cars. Wouldn’t it be nice to start with a “car” and build up the specifics of a Saturn?

Inheritance is a feature of OOP programming that enables us to do just this. By inheriting all the common features of a car into a Saturn, it’s not necessary to reinvent the object (car) every time.

In addition, by inheriting the features of a car into the Saturn through an added benefit called polymorphism, the Saturn is also a car. Now that may seem obvious, but the reach and scope of that fact is enormous. Under traditional programming techniques, you would have to separately deal with each type of car—Fords here, GMC there, and so on. Under OOP, though, the features all cars have are encapsulated in the car object.. When you inherit car into Ford, GMC and Saturn and you can then polymorph them back to car, and much, if not all, of this work is eliminated.

Objects as Multiple Entities

One of the pitfalls that you have probably fallen into as a procedural programmer is thinking of the data in your program as a fixed quantity. A perfect example of this is the screen. Usually procedural programs tend to write something to the (one) screen. The problem with this method is that when you then switch to a windowing environment and have to write to multiple screens, the whole program is in jeopardy. It takes quite a bit of work to go back and change the program so that the right data is written to the window screen.

In contrast, OOP programming treats the screen not as the screen but as a screen. Adding windows is as simple as telling the function it’s writing to a different screen object.

This demonstrates one of the aspects of OOP programming which saves the most real programming time immediately. When you become an OOP programmer, you begin thinking of dealing with objects. No matter if there’s one or 100 of them, it doesn’t effect the program in any way. If you’re not familiar with OOP programming, this may not seem to make sense. After all, what you are saying to yourself is, “If I have two screens, when I go to print something to the screen I need to be sure to position it correctly on the correct screen, and pay attention to user interaction to each different window.”

Believe it or not, under OOP the need to do this is washed away. Once the elements of a window or screen are abstracted sufficiently, when you write the method it’s irrelevant which screen your writing to. The window object handles all of that for you.

Organizing Code

OOP programming organizes your code elegantly because of two key factors:

Objects and How They Relate to Java Classes

At the heart of Java is support for these objects you have been hearing about. They come in a form called a class. Actually, there is a Java class called Object which all classes inherit from, so all classes literally are Objects.

Objects are instances of classes. In this sense, classes can be thought of as a template for creating an object. Take as an analogy a rectangle. A rectangle has an x,y location, height, width, move method, and resize method (for shrinking or enlarging the rectangle). Now when you write the code for the rectangle, you create it in a class. However, to take advantage of the code, you need to create an instance of that class. The instance is a single Rectangle object.

Building an Hierarchy: A Recipe for OOP Design

When setting out to develop an OOP program for the first time, it is often helpful to have a recipe to follow. Developing good OOP structures is a lot like baking a pie. It’s first necessary to gather all the ingredients, then begin assembling each portion of the pie.

Break Down Code to Its Smallest Entities

When writing an OOP program, it’s first necessary to figure out which ingredients are needed. For instance, if you were writing an arcade game, it would be necessary to figure out everything that would be in that game: creatures, power pieces, the main character, bullets, and so on.

Once you have assembled these pieces, you need to break them down into all of their entities, both data and functional. For this example, if you were setting out to write the arcade game you might create a list like this for the four items:

Look for Commonality Between the Entities

The next phase of developing an OOP structure is to look for all the common relationships between each of the entities. For instance, right away you might recognize that the primary difference between the creatures and the main character (aside from how they look) is who controls it. Namely, the creatures are controlled by the computer, and the main character is controlled by the user. Wouldn’t it be great if you could write most of the code once for both the creatures and the main character once, and then just write separate code for moving them?

If that’s how you feel, keep reading, because that’s exactly what the OOP paradigm is all about.

Look for Differences Between Entities

The next step is to find the differences between the entities. For instance, the bullets move and the power pieces stay put. Creatures are controlled by the computer, and the main character is controlled by the user. What you are looking for in all of this are relationships that unite and separate all of those entities in your program.

Find the Largest Commonality Between All Entities

The third step is to find the largest common relationship between all the entities in your program. Rarely is it impossible to find any common relationships among all objects. However, it is possible that you may find that one entity is just completely different.

Looking at the game example, what do you see that all four objects have in common? What can you group together that all of the objects have in common? A quick list might be: size, the ability to move around (the power piece doesn’t really need to move, but it wouldn’t hurt if it could), and location.

Is that all that they have in common?

No, perhaps the most obvious wasn 2't even (intentionally) listed before: the ability to be drawn to the screen. This ability is so obvious you may just plain miss it. Don’t forget to look at the obvious.

With these entities, I would suggest creating a class called Draw_Object. The class would contain all these items.

Put Remaining Common Objects Together and Repeat

The next phase is to put objects that still have things in common together. All of these objects will now inherit from the class that contains all the Draw_Object information.

At this point, the power pieces and the bullets probably split from the creatures and the main character. Now, take the remaining objects and repeat the recipe again.

When I went through the next phase, I found that the only real difference between the power pieces and the bullets was their size and how fast they moved (the power pieces at speed 0). Because these were primarily minor differences, I decided to combine them into one class.

When I looked at the creatures and the main character, I decided that the main character contained everything that a creature did plus some, so I would inherit the Creature class in the Main_Character class.

The final class hierarchy is shown in figure 6.1. There are countless variations on this; see what you come up with.


FIG. 6.1

The hierarchy for the game enables you to save a lot of coding.

Using Objects to Add As Many or Few As Desired

When writing a game, it is often highly desirable to be able to add as many attack creatures as a particular board wants. Now, because the creature class encapsulates, all the information necessary to create a creature, all that is necessary is to add another creature to the list.

You can think of this step as if you were creating another variable. If your already a programmer, you’re probably very used to just creating another integer variable any time you need one. Now you can create another creature any time you like.

Java Isn’t a Magic OOP Bullet

The focus of this chapter has been to introduce the concepts of good OOP. The chapter has intentionally avoided complicated coding implementations. The rest of this book should help you fill in that portion.

Now that you have seen many of the fundamentals of OOP programming at a surface level, let’s establish why I went through all of this: Java isn’t a magic bullet to creating OOP programs. While Java embraces the OOP paradigm, it is still possible (and not unusual) to write structured programs using Java.

By introducing OOP at this stage, I hope that you can break the bad habits of structured programming before they begin. You need to remember that OOP is a different way of thinking as much as it is a different way of programming. Throughout this book, there are applets and applications which are written in both ways. Look for those programs that are broken into multiple pieces. Then when you think you understand OOP, reread this chapter and see if there are any more insights that are brought to mind.


Previous PageTOCNext Page

| Previous Chapter | Next Chapter |

| Table of Contents | Book Home Page |

| Que Home Page | Digital Bookshelf | Disclaimer |


To order books from QUE, call us at 800-716-0044 or 317-361-5400.

For comments or technical support for our books and software, select Talk to Us.

© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.