Object Oriented Design: A Primer

Introduction to Object Oriented Design

I remember when I first transitioned from traditional Procedural Programming to Object Oriented Programming (which may be abbreviated as OOP), the general idea of it seemed to be a bit odd. After all, a computer program is defined as a set of instructions for the computer to follow; what’s all this talk of classes and objects? Before we define Object Oriented Programming, it will be helpful to first gain a clear understanding of what Procedural Programming is, so we can then understand why OOP is so useful for certain things. Before I begin, I’d like to mention that this article will be using the Java programming language for the examples. The examples could easily be reproduced in other Object Oriented Programming languages (such as C++, C#, Visual Basic, or Python), but for simplicity’s sake I will only be using Java. Just in case you have no experience with Java, I will provide basic instructions on how to install the JDK (Java Development Kit) for all major operating systems; we will actually be using an IDE (Integrated Development Environment) that comes bundled with the JDK. This won’t primarily be a tutorial on the Java language itself, but if any aspects of the Java language confuse you, there are plenty of resources available online which may help you figure it out. This article is primarily intended for intermediate level programmers, although both beginner and experienced programmers alike may still be able to learn something new from it. If you’re a complete beginner, you might benefit by building a basic foundation with Java first (variables, conditional statements, and methods/functions).

Procedural Programming makes use of procedures (also known as subroutines, or functions) which carry out one or more computational instructions. You don’t need to rewrite all the code for the procedure/function/ subroutine each time you need its functionality. Instead, you define it once and then you may use it again anywhere you would like. All you need to do is call the function, and then the code for that function is executed. By having different functions which each represent different things our program can do (such as adding up all the numbers in an array of integers, or removing all of the white space from a string) we’re able to structure our program more effectively than if we couldn’t make use of functions. After all, without the ability to create named functions/procedures, our program would basically be one big giant main function of spaghetti code. I still recall my early days of programming, back when I put all of my code into the main function – it was quite sloppy and confusing. As time went on, I realized that it’s wiser to create other functions, each with its own purpose.

Object Oriented Programming also makes use of procedures/subroutines/functions/methods. However, instead of having the program consist primarily of functions, Object Oriented Programming consists primarily of classes (which essentially define objects). It’s not that functions don’t exist within OOP, but rather that procedures/functions/subroutines exist within the context of a class. It’s quite likely that you’re already getting a little lost – so let’s take a step back and dig deep into the meaning of classes and objects.

Classes and Objects

Downloading & Installing the JDK The concepts of classes and objects are the most fundamental concept to understand in the world of Object Oriented Programming. There are other important concepts as well (which we’ll cover later on in the article), but understanding classes and objects is essentially a prerequisite to understanding the other ideas of OOP.

The great thing about Object Oriented Programming is that it allows us to model objects of the real-world in a way that’s consistent with the way they actually work. OOP may also be used to model things that don’t even exist in the physical realm as well. However, for our initial examples, I will model real objects from the physical world to make everything easier to understand. The entire universe consists of objects. From the viewpoint of OOP, even the universe itself could be considered an object. Objects may contain other objects – just like how the universe contains galaxies, which contain solar systems, which contain planets, which contain people/places/things, and those people/places/things contain things as well (such as components or body parts). You could really break down the object oriented view of the universe all the way down to the atomic level of protons, neutrons, and electrons (even subatomic particles). The whole universe is essentially an extremely gargantuan and intricate object oriented program. As a matter of fact, the ability to see everything in the universe from an object oriented perspective is key to developing profound skills with Object Oriented Programming.

The concept of an object is quite intuitive to all of us, although the concept of a class may be a bit more difficult to grasp. Think of a class as a blueprint for an object. For example, a class for car objects is basically a blueprint (or definition) for a car object. As you may have guessed, each different type of car would need to have a different blueprint, since not all cars are the same. The two main different types of things that objects are made up of is state and behavior. The state of an object is determined by its fields (which are stored in variables or objects), and the state represents the properties of an object. For example, a person object could have different properties, such as age (which could be stored in an integer variable), name (which could be stored in a string object), and date of birth (which could be stored in either a date/time object or a string object). In a nutshell, the state represents information about our class, and the state may (but not necessarily) change throughout the lifetime of an object. On the other hand, behavior represents the things that our object can do; the behavior of our objects is the actions that they may perform. In Java, we refer to the behaviors of our objects as methods. Methods aren’t really much different from the idea of functions in other languages; if you’ve never heard of methods before, simply think of them as functions, procedures, or subroutines. The methods represent procedures that we may call for our object to perform (a method that our object uses to do something). As stated earlier, procedures still exist within Object Oriented Programming, but they generally exist as part of a class, rather than by themselves. Just about everything in Java is contained within classes/objects.

So let’s go back to the example involving a car. A car class could have properties such as cylinders (V4, V6, V8, V12, etc.), maximum speed, and license plate. If the class is being used for an application that sells cars, each car could also have properties such as the listed price, quantity in stock, etc. The behaviors of our car could include things like accelerate, brake, and turn (a bit simplistic, but I don’t want to make things too complicated).

Now that we have a basic understanding of classes and objects, we can proceed to understand main ideas of Object Oriented Programming: encapsulation, inheritance, composition, and polymorphism. However, before we get into all of that, let’s install the JDK on our machines. It will be tough to understand all of these concepts without seeing them in action within an actual program, so let’s get our development environment ready.

If you already have the JDK installed and are comfortable with Java, please proceed to the next section.
First, visit the Java download page at:

It’s possible that the URL for their download page may eventually change – if the above link doesn’t work then just Google “Install JDK” and you should find the proper download page with relative ease. As of right now, the download page appears like Figure 3-1, in which you should click the Download button that I outlined in red. We’re actually going to be downloading the “JDK 8 with NetBeans” bundle. NetBeans is an IDE (Integrated Development Environment) for Java. Although I often just write Java programs in Vim and execute the programs on the command line, it’s helpful to also learn to use an IDE.

download page

Figure 3-1

You should also note that the current version of the JDK will change over time. However, this shouldn’t be much of an issue since we’ll be mostly working with core features of the Java language. It’s unlikely that Oracle would want to release a version of the JDK which wouldn’t be able to run programs that have any of their core features. Even if this does happen, then you should at least be able to find an archived version of the JDK version 8.

On the next page, you simply need to accept the License Agreement (nobody actually reads these agreements, but you can if it makes you feel better) as in Figure 3-2. Then, you simply download the file associated with your particular operating system (Linux, Mac, or Windows).

accept the License Agreement

Figure 3-2

After that, just execute the file; the installation process should be fairly easy to navigate on your own. If you have any trouble, there are plenty of resources for support. I’ll explain how to use the NetBeans IDE as I go along, and you may use any other IDE (such as Eclipse or IntelliJ). However, only use a different IDE if it’s an IDE that you’re comfortable/experienced with, since you might have to adapt the lesson to suit your IDE.

Our First Java Application

I feel that I should at least walk you through creating a basic Hello World application before jumping into heavy OOP with Java. Technically, even our Hello World program is within the realm of Object Oriented Programming, as literally everything in Java is an Object. The program itself will be a public class named HelloWorld, and the main method of that class is what executes when we run it. First, go to File > New Project within NetBeans IDE 8.1, as in Figure 4-1.

New Project within NetBeans IDE

Figure 4-1

Then, select Java Application from the Java category, as in Figure 4-2.

Java Application

Figure 4-2

After you click the Next button, set the Project Name to HelloWorld and click Finish. At this point, you already have an application built, except that the application doesn’t actually do anything. We are essentially left with an empty skeleton, as in Figure 4-3. Keep in mind that the colors of my environment may look different – I prefer dark backgrounds with bright text. To select this color scheme, go to Tools > Options > Fonts & Colors, and then select City Lights (or another color scheme that you prefer).

selecting a color scheme

Figure 4-3

The first line of code says that this Java class is part of the helloworld package. The second line of code creates a public class named HelloWorld. The word public is an access modifier, which is used to specify how accessible a class is by other classes. Public is the least restrictive, as it means that any class may access it. Keep in mind that access modifiers aren’t only used with classes, but also variables and methods.

Within the HelloWorld class, we have a public static void method named main (which can take string arguments). Void means that the method doesn’t return any value (it simply executes code and then exits the method without returning anything). Static means that the method can be called without instantiating a HelloWorld object; it can be called directly from the HelloWorld class. If you don’t have any Java experience yet, much of what I’m saying should confuse you, but everything will start to click if you just keep going.

Within our main method, all we have is a comment which says “TODO code application logic here”. Comments are code that isn’t actually executed; to make a long story short, nothing actually happens in our main method. So let’s erase that useless comment and replace it with a line of code which will display “Hello World!” in a console. This line of code is System.out.println(“Hello World!”); and I have displayed all of the code for our application in Code Listing 4-1.

You may have noticed that I have erased all of the default comments of the application. I prefer to use comments that actually help me, and the default comments that NetBeans put into our code don’t serve any purpose for me. Exactly how you comment your code is really up to you. However, comments are especially vital in large and intricate applications. Even though you may understand how all of your code works at the time you write it, you could go back to it several months later and forget how everything works. You will still probably be able to figure it out without the comments, but comments make the process of retracing your steps much easier. Beyond that, if you’re working with a team of programmers on an application, it will help the other programmers understand the code too.

Run the application by going to Run > Run Project or clicking on the green play button. The console should display “Hello World” as in Figure 4-4.

console display

Figure 4-4

Object Oriented Programming Principles In Action

As you may have noticed, our Hello World application is quite pathetic – it doesn’t really “do” anything (besides saying “Hello World!” in the console) and is about as simple as an application could possibly get. With that being said, the Hello World program is a traditional and sacred classic amongst programmers. However, it’s already time for us to move on to bigger and better things.

Create a new project named “VehiclesProject” (using the same steps that we used to create the HelloWorld project). Unlike our Hello World project, we won’t be modifying Java file that it creates automatically (VehiclesProject.java) until later on. We’ll use VehiclesProject.java as the entry point of our application, but we need to build some of the other classes in our project first. The general idea of this project is to see Object Oriented Programming principles in action with different types of vehicles – automobiles, boats, and planes.

Let’s first ask ourselves: What do automobiles, boats, and planes have in common? The first thing that will come to mind is that they’re all different types of vehicles. Therefore, we will create a parent class named Vehicle which will be used as the foundation for all of the other classes. A parent class (which may also be called a superclass, or base class) is a class which other classes are inherited/derived from. Our Vehicle class should also be an abstract class, since we can’t instantiate an object of type vehicle in the real world. For example, if someone asks you “What kind of car do you drive?”, you won’t answer “A Vehicle” (vehicle is an example of an abstract class). Rather, you will answer with something like “A 1994 Honda Civic”. A 1994 Honda Civic is a concrete example of a car that exists – while the idea of a car is an abstract concept. Both the concrete/specific implementations of cars, as well as the general idea of a car are both useful to us as programmers. Some of our code can be tailored to only a specific type of car (such as a Honda Civic), or we can also write code that effects all cars, regardless of what kind of car you drive. A class that’s used as a blueprint for an Object that can actually be instantiated is known as a concrete class.

Let’s go back to the concepts of parent classes and children classes. These concepts represent inheritance, which allows one class to inherit all of the fields and methods of it’s parent. I should note that fields and methods which are declared with the private access modifier can’t be modified by any other class, including a class which inherits from it. Using the private access modifier to restrict other classes from accessing it is an example of encapsulation, which is the Object Oriented Programming concept of information hiding. We won’t deal with much encapsulation in this article, but it’s an important topic to research if you want to further your OOP skills.

Back on the subject of inheritance, Let’s pretend we had classes for 5 different cars: a Honda Civic, a Toyota Corolla, a Pontiac Grand Prix, a Hyundai Sonata, and a Volkswagen Jetta. As you may guess, there would be a ton of code that would be exactly the same for each car, since they’re all basically the same. Instead of having to rewrite all of this duplicate code in the classes for each car, we can put everything that all cars have in common into a parent class named Car. Therefore, each class which inherits from Car only needs code that’s specific to that particular type of car. Likewise, we could put all fields/methods that all Pontiac cars have in common in a Pontiac class. Then we could have a Grand Prix class which would contain everything in common between all Grand Prix submodels and years. Finally, the concrete classes would be things like a 2006 Pontiac Grand Prix. The design of our application won’t actually get this complicated – but I just want
to explain how this all relates to the real world.

In addition to inheritance, composition is also used in designing classes. The difference between inheritance and composition is that with inheritance, we literally inherit everything from the parent class. With composition, we simply contain the other class as a component of our class (it’s not a parent, it’s just a component). Inheritance is often used in cases where composition should be used, so you must be careful to not go overboard with inheritance within Object Oriented Programming. For now, don’t worry too much about all of that – simply have fun, experiment, and get a feel for how OOP works. As time goes on, you’ll gradually improve and figure out how to use each concept. The main things to keep in mind is that inheritance should represent an Is-A relationship (as in a Pontiac Grand Prix Is-A Car), whereas composition should represent a Has-A relationship (as in, a Pontiac Grand Prix Has-A Steering Wheel).

Let’s go back to NetBeans to start developing our project. On the left menu of the IDE, expand the VehiclesProject by clicking on the plus sign next to it. Next, expand “Source Packages”, and then expand the vehiclesproject package. Finally, right click on the vehiclesproject package, and then select New → Java Class as in Figure 5-1.

New Java Class

Figure 5-1

Set the name of our new class to Vehicle and then click Finish as in Figure 5-2.

Set the name

Figure 5-2

The fields and methods of our vehicle class should be things that are universal among all vehicles, regardless of whether it’s an automobile, boat, or plane. All vehicles have weight, color, and price – this is universal regardless of the specific type of vehicle. The weight, color, and price will certainly vary from vehicle to vehicle, but they’re properties similar between all vehicles. Wheels, on the other hand, only exist on cars and planes; boats don’t have wheels. Therefore, we won’t include wheels as part of our vehicle class. We can also create a constant named maxSpeed that will store the maximum speed the vehicle is allowed to travel, and a field named currentSpeed which stores the current speed of the vehicle. We can also have a field named direction which stores the direction we’re currently heading. We can use the idea of a clock to keep track of where we’re going, with 12:00 representing North, 6:00 representing South, 3:00 representing East, 9:00 representing West, and so on. We won’t be using the minutes in this example, although if you did the direction could be much more accurate (60 * 12 = 720 possible specific directions, which is accurate to a half of a degree in a 360 degree circle). I just didn’t want to make the direction algorithm overly complicated for this example, and even splitting a circle into 12 points is accurate enough to store the general direction of our Vehicle (it’s three times as accurate as using just North, South, East, and West).

Although the Vehicle eventually will be an abstract class, let’s first start it off as a concrete class so we can play with it a little bit (we can’t actually instantiate objects of abstract classes). After we complete the Vehicle class, we can convert it to an abstract class and then further develop our class structure.

The code for a concrete version of our Vehicle class is shown in Code Listing 5-1.

The first lines of code in the body of our Vehicle class declare the various fields. They are fairly self explanatory, as they identify the weight, color, price, maximum speed, current speed, and current direction of our vehicle. Choosing variable names (or method names) that accurately describe their purpose is always wise. Commenting your code is an important thing to do regardless, but choosing variable, method, and class names that “make sense” reduces the need for heavy commenting (which not only saves time, but it also makes the code easier to read and less bulky). Next, we specify a constructor of our vehicle. A constructor is essentially a method that gets called when our object is created. We identify our constructor by using the public access modifier followed by the name of our class (in this case, public Vehicle). Then, we have all the parameters to our function listed in parenthesis, just like any other method. In this case, we’re just using our constructor to initially set the various fields of our Vehicle. However, you may also call methods, perform conditional logic, execute loops, and more from the constructor as well. In a nutshell, the constructor is simply a method that gets called when our object is initially constructed (hence the name constructor). You may also notice the use of the this keyword. In Java, the this keyword refers to the object itself. In Visual Basic, the equivalent term is actually Me, since it essentially allows the object to refer to itself. Although people sometimes use the this keyword when they don’t need to just for clarification, it is sometimes necessary to remove ambiguity. The variable names within the parameters of the constructor are identical to the names of the Vehicle fields. Therefore, without the this keyword, it becomes unknown whether we’re referring to the Vehicle fields or the arguments passed to the constructor. We could simply use variable names that are different from our field names, and that way we wouldn’t need the this keyword. I personally find the this keyword quite convenient, since that way in my constructor definition it’s quite obvious which parameter matches up to which field.

Next, I define some methods that enable our Vehicle object to perform different actions: accelerate, decelerate, turn to the left, and turn to the right. A real Vehicle would need to do more than just these basic things, but for simplicity’s sake I made the class easy to digest. Not only that, different types of vehicles may perform these actions in totally different ways; planes decelerate much differently than the way cars decelerate. In this case, I took the easy way out and simply passed the mph to accelerate/decelerate as arguments to the functions. Likewise, for turning, you pass the number of ticks to the turnClockwise or turnCounterClockwise methods. Remember that our direction is stored like a clock, with 12:00 for North, 3:00 for East, 6:00 for South, and so on. Therefore, if we’re currently traveling East (3:00), then turning clockwise 3 ticks would change the direction of our vehicle to South (6:00). On the other hand, if we were traveling East (3:00) and we turned counter-clockwise 6 ticks, then that would change our direction to West (9:00). Our direction variable is even more accurate than just North/South/East/West. For example, 10:00 and 11:00 would represent the North-West directions. The code of the turnClockwise and turnCounterClockwise methods may look a bit more intimidating than the accelerate/decelerate methods, so I have included plenty of comments to help you understand exactly what’s happening at each step.

I also added some code to VehiclesProject.java, so we can test out our new Vehicle class.

When you run this code, your output should look like Figure 5-3.


Figure 5-3

I added comments to the code in Code Listing 5-2 which should make everything quite clear, but I do want to analyze the code a little bit. Let’s take a look at the first line of code in our main method:

Vehicle vehicle = new Vehicle(897.12, “Blue”, 10.00, 100);

Basically, we’re creating a new Vehicle object named vehicle. In this case, we named our object vehicle, but we could have named it Honda, gasGuzzler, or bessie. The new operator essentially tells the compiler that we need to create a new object of the class which follows the new operator. As a matter of fact, if all we wanted to do was create a new Vehicle object, we could simply write:

new Vehicle(897.12, “Blue”, 10.00, 100);

However, we don’t want to just create a new Vehicle object, we also want to store it in some sort of reference
(in this case, the reference, or name of our Vehicle object is simply vehicle). This way, we have some sort of way to access our Vehicle object after creating it. There can be cases where you don’t need to store any reference to an object that you create, but in our case we want the reference. The new operator calls the constructor of the given class with the various arguments passed to the constructor. In Code Listing 5-2, we use the arguments 897.12 (a double value representing the weight of our Vehicle), “Blue” (a String value representing the color of our Vehicle), 10.00 (a double value representing the price of our Vehicle), and 100 (an integer value representing the maximum speed of our Vehicle). These values are used to set many of the fields of our Vehicle object. Remember, the Vehicle.java file is the Vehicle class. Using new operator with our Vehicle class is what actually instantiates a Vehicle object. Again, a class is really just the blueprint (or definition) of an object; it’s not an actual instance of the object.

The rest of the lines of code in Code Listing 5-2 are quite similar, as they just call different methods of our Vehicle object. Before/after each change to vehicle (our Vehicle object), we display the value of the relevant field. For example, the first four methods called are the turnClockwise and turnCounterClockwise methods of our Vehicle object. Each time we turn, we display the value of the direction field, so we see how the methods called actually change the direction of our object. After that, we use the accelerate and decelerate methods to change the speed (the value stored in vehicle.currentSpeed) of our object. Remember that vehicle.currentSpeed refers to the currentSpeed field of the Vehicle object named vehicle. Just like in our Hello World program, System.out. println() is used to display the output to the console. One interesting thing I wanted to note: our last call to decelerate has an argument of 10, which drops our speed to -3 mph. This could appear to be a bug, since a vehicle can’t really travel negative miles per hour. However, we could also potentially use a negative value to indicate that the vehicle is driving in reverse. In other words, it’s not a bug, it’s actually a feature!

I had mentioned earlier that Vehicle should actually be an abstract class, since in the real-world we can’t just drive a generic “Vehicle” object, it’s always some type of concrete implementation of a vehicle (such as a Harley Davidson, a Honda Civic, or a school bus). Let’s change the Vehicle class to an abstract class, which is actually quite easy. Simply change second line of code Vehicle.java where it says “public class Vehicle” to “public abstract class Vehicle”. This tells the compiler that it’s an abstract class. The code for Vehicle.java should now be the same as Code Listing 5-3.

Let’s try to run VehiclesProject.java again. Uh oh – it’s not working anymore! In VehiclesProject.java, we try to instantiate a Vehicle object, but we aren’t allowed to create/instantiate objects of abstract classes (and Vehicle is now an abstract class). Therefore, we receive RuntimeException with the error message “Uncompilable source code – vehiclesproject. Vehicle is abstract; cannot be instantiated” as in Figure 5-4.


Figure 5-4

This error should be expected, since we don’t want to create plain Vehicle objects, we’re simply using the Vehicle class as a foundation for subclasses (such as cars, boats, or airplanes). We have once again run into the concept of “it’s not a bug, it’s actually a feature!”. Appearances may be deceiving.

Before we define any concrete classes that we can actually work with, let’s create one more abstract class named Car. The Car class will contain things that all cars have in common. This way, we can avoid having to write a ton of duplicate code in the class definitions for each specific car that we create. I’ve created a Car class that you may copy into your project, which is shown in Code Listing 5-4.

Our Car class is much simpler than a real car, as it only contains four wheels and an engine. We’ll take a look at the Wheel and Engine classes that I created in a bit, but all you really need to understand right now is that the Wheel class represents a wheel and the Engine class represents a car engine. We have a separate Wheel object for the front left, front right, rear left, and rear right (each of the four wheels on the car). One great thing about Object Oriented Programming is we don’t always need to understand exactly how an object works under the hood, sometimes we only need to know how to use it. For example, we don’t need to know how the engine of our car works to get to our destination, we only need to know how to drive the car.

You may notice the use of the extends keyword; extends is the keyword which enables us to perform inheritance. By saying “Car extends Vehicle”, we’re telling the Java compiler that the Car class inherits from Vehicle class, that the Car class is an extension of the Vehicle class, and that it’s a sub-type of Vehicle (all three of these phrases say essentially the same thing, just in a different way for added clarity). Additionally, since Car is technically a Vehicle too (just a more specific type of Vehicle), we still need all of the values necessary for the Vehicle object constructor. Therefore, we have more parameters than just the Wheels and an Engine. We also have the weight, color, price, and maxSpeed parameters, so that we can satisfy the requirements for constructing our Vehicle. The first line of our constructor calls the constructor of our super class (another way of saying parent class, the class which we are inheriting from):

super(weight, color, price, maxSpeed);

The super keyword can also be used much like the this keyword, except instead of referring directly to the object itself, you’re referring to the parent class of the object. As you can see, we’re passing the four arguments that are needed for the Vehicle constructor: the Vehicle weight, the Vehicle color, the Vehicle price, and the Vehicle maxSpeed. Just in case you’re wondering, Java actually builds the super class objects first (starting at the top of the class hierarchy), and gradually works it’s way down to the class of the concrete object being instantiated. We may also use the super keyword for other reasons besides calling the constructor of our super class. For example, super.maxSpeed within our Car class would refer to the maxSpeed value of the Vehicle class. We can actually alter maxSpeed directly from within Car, but if the maxSpeed was declared private within Vehicle, then we would need to use the super keyword to access it. If any of these keywords (such as super or this) confuse you, please don’t hesitate to explore other resources on the web which explain these concepts in further depth.

You may also find the following line of code to be a bit interesting:

protected abstract void shiftGears(String gear);

This is an example of an abstract method. An abstract method may only exist within an abstract class, and they don’t have an actual definition (hence the semicolon after the method signature, rather than the curly brackets which would hold the method body). An abstract method needs to be defined by any concrete class which inherits from the class containing the abstract method. Essentially, it’s saying “I don’t have a definition for how to shiftGears right now, but you’re going to need to figure out a definition for shiftGears before you actually create a real car object.” Abstract methods are useful when there is a common behavior between different subclasses, but not all subclasses will necessarily define that method/behavior in the same way. Basically, we’re making it clear that we require any car to have some method of shifting gears. On the other hand, we aren’t saying exactly how the method has to work (besides specifying that an argument for the gear you want to switch to should be passed to the method). We leave each class that inherits from Car free to define this method in any way that they want. However, we do require that it does get defined. Abstract methods and abstract classes are similar to the idea of interfaces, since they can’t actually be instantiated or used directly. Interfaces are outside the scope of this article, but if you choose to learn about Java interfaces, it should be easier now that you understand the concept of abstraction. Abstraction is truly central to Object Oriented Programming, and mastering the art of abstraction may help you see the glue which holds everything in the universe together (in an abstract sense).

With all that out of the way, let’s take a quick look at the Wheel class (Code Listing 5-5) and the Engine class (Code Listing 5-6).

The Engine class doesn’t even need much explanation, as it’s nothing but an empty class. If you’d like, you can actually study the structure of a car engine and fill in the class definition of Engine with components/behaviors of a real engine. This would be a great exercise if you haven’t done much with Object Oriented Programming, although I didn’t feel it necessary to complicate the lesson by completing (and then explaining) the definition of the Engine class. Beyond that, I’m not a mechanic or expert on automobiles in any way, so I would have to learn quite a bit about engines to make an elegant design. Which brings me to an important point – it’s important to have a deep understanding of the objects that you’re modeling in your code. Otherwise, you will either leave out important pieces or add things which are unnecessary to your class definitions. After all, if you don’t know how an engine actually works, it will be tough to write a computer program that simulates a car engine.

The Wheel class does have a definition, although it doesn’t have any methods. The definition of our Wheel class consists almost entirely of fields. The first field is tirePressure, which as you may guess, represents the pressure of a tire (which if I remember correctly is measure in psi, or pounds per square inch). The rest of the fields relate to the wheel size; you can refer to the URL http://www.discounttire.com/dtcs/ infoWheelSize.do to get an understanding of the different components of that value. Although you could view the wheel size as a single value, it’s actually made up of the wheel diameter, width, bolt pattern, offset, and finish. Just like our other classes, we use our constructor to set the initial values of the fields.

The way that we use Wheel and Engine objects in the definition of our Car class is an example of the Object Oriented Programming concept known as composition. Although we have previously briefly covered composition vs inheritance, they’re quite crucial to OOP and worth a second look. Composition is usually considered more suitable than inheritance in most situations, and it’s usually suggested to primarily rely upon composition when creating classes. However, inheritance is a very unique concept and is still quite fundamental to Object Oriented Programming, which is why I’ve placed so much emphasis upon understanding it. The main difference between composition and inheritance is that inheritance is used in “Is-A” relationships, while composition is used for “Has-A” relationships. For example, a car “Is-A” vehicle (inheritance). On the other hand, a car “Has-A” engine, and it also has wheels ( composition). It wouldn’t make sense to say that a car is a engine, since there’s more to it than just an engine. Likewise, it wouldn’t make sense to say that a car has a vehicle, since a car literally IS a vehicle. However, some programmers write their code in a way that they use composition in this way; as in having a reference to a Vehicle object in the definition of their Car class, rather than inheriting from Vehicle. I personally find this to be poor design, and if you aren’t going to take advantage of what OOP has to offer, then you might as well stick to procedural programming. It’s easy to fall into the trap of thinking that inheritance is bad simply because it’s easily (and often) abused. Inheritance is like any other tool; it’s very useful in programming if you know how to use it. On the other hand, if you use inheritance to represent “Has-A” relationships, or if you design your parent classes in a way that puts your subclasses in too much of a box, then problems can (and probably will) result. For now, if you’re still new to Object Oriented Programming, I wouldn’t worry too much about whether you’re “doing it right” in terms of either composition or inheritance. After all, you’re going to make plenty of mistakes on your path towards mastery, and mistakes are often our most powerful teachers. Just keep programming, and as time goes on you’ll figure it all out.

Something Tangible – Concrete Classes

Up to this point, we’ve been dealing with a lot of abstraction. Understanding abstraction and how to use it is important in the world of Object Oriented Programming. Ultimately though, we need something tangible that we can actually use. Concrete classes represent things that can actually solidly (concretely) exist, as opposed to things which only exist as abstract concepts. If you think of your class hierarchy like a tree, the concrete classes represent the leaves of the tree. The parent classes (in our case, Car and Vehicle) would all represent twigs and branches on the tree. The trunk of the tree is actually the Object class, which is the most foundational class in Java that all classes automatically inherit from. In essence, everything in Java is an Object, and inherits from the Object class.

Let’s take a look at a couple concrete classes that I created which inherit from our Car class, which I’ve displayed in Code Listing 6-1 and Code Listing 6-2.

The NissanSentra and ToyotaCorolla classes are quite similar. Their fields are exactly the same, which include year (the year the car was manufactured), miles (the total number of miles on the odometer), mpg (miles per gallon of fuel), and gear (the current gear that the car is in). The constructors for both classes are also identical, which start with a call to the super class (Car) and then set the fields. The toString methods are almost exactly the same. If you don’t know the purpose of the toString method, no need to worry; as I’ll explain it shortly.

The primary difference between the NissanSentra and the ToyotaCorolla classes is in how the shiftGears method is implemented. As I mentioned earlier, the shiftGears method is an abstract method of our Car class, and needs to be implemented in any class which inherits from Car. However, Car makes no requirements about how this method needs to be implemented, so each child class is free to implement the method in any way that they choose. The Nissan Sentra simply sets the gear of the car to whatever gear is passed as an argument to the shiftGears method, and then prints a line to the console explaining that we changed gears. In the Toyota Corolla, we check to make sure that the value passed to shiftGears is valid (P for Park, R for Reverse, N for Neutral, 1 for first gear, 2 for second gear, etc.) It may actually be better to consider Park, Reverse, and Neutral to be separate from the driving gears (1, 2, 3, etc.), but for simplicity I have just combined them into one.

Let’s check out a new and improved version of VehiclesProject.java (shown in Code Listing 6-3) that uses our concrete classes. We had previously broke VehiclesProject.java when we turned our Vehicle class into an abstract class, since we can’t instantiate abstract objects. The console output of VehiclesProject.java is shown in Figure 6-1.

console output of VehiclesProject.java

Figure 6-1

The output of our program is quite similar to the original VehiclesProject.java. We show the direction and speed of two different vehicles after applying turns, acceleration, or deceleration to them. One vehicle is a 2001 Nissan Sentra named joe, and the other is a 2013 Toyota Corolla named bob.

A quick aside: I’m aware that names should start with an uppercase letter in English, but this isn’t necessarily true with Java. As a matter of fact, the convention of most Java programmers is to start variable names with a lowercase letter. Programming conventions, in a nutshell, are a way of specifying guidelines for naming variables, using whitespace (spaces, tabs, and new lines/carriage returns), comment style, coding principles, and programming style in general. It’s always important to be careful when discussing programming conventions; as there isn’t any one right way to write your code. Arguing over conventions can be like arguing over politics and religion. Regardless, it’s definitely wise to follow some sort of conventions within your code, since general consistency is crucial to writing good code. Which conventions you choose to follow are entirely up to you, and as time goes on you may develop your own personal style. If you’re coding for an employer, then they may specify guidelines and programming conventions that you’ll need to follow (until you become the lead programmer and get to make some of your own rules); so you might not always have much of a choice in terms of which conventions (or even programming languages) that you use.

Back to the Object Oriented Programming: You may notice there are three other methods besides main in VehiclesProject.java (previously, the only method was our main method). We have the displayDirection method, which displays the direction of the Car passed to it as an argument. Then, there’s the displayNissanSentraSpeed method, which displays the speed of the Nissan Sentra passed to it. Finally, there’s the displayToyotaCorolla speed method, which displays the speed of the ToyotaCorolla to it. The difference between the displayDirection method and the two methods for displaying speed help illustrate the concept of polymorphism. Polymorphism refers to the ability of one object being able to morph into more than one form (poly meaning more than one). In other words, a ToyotaCorolla could be treated as a ToyotaCorolla, or a Car. It could even be treated as just a Vehicle, which is also true for a Nissan Sentra. This is quite useful, since we can write one method that works on all Vehicle objects (such as displayDirection), instead of having to write separate methods for every single specific object (such as the methods for displayNissanSentraSpeed or displayToyotaCorollaSpeed methods), which could involve tons of duplicate code that weighs the program down. At the same time, sometimes we only want a method to only work with one specific class, so it’s also useful to be able to specify a particular concrete class. Converting an object into its parent class is known as upcasting. Likewise, downcasting involves converting an object into it’s child class. Upcasting tends to be a safer operation than downcasting. For example, you can upcast a Nissan Sentra to the Car class, and then accidentally attempt to downcast that Car object to a Toyota Corolla (I know it sounds crazy, but I’ve accidentally done things like this before). However, just because a Nissan Sentra can also be considered to be a Car, doesn’t mean it can also be considered to be a Toyota Corolla. Again, just because all Toyota Corollas are Cars, doesn’t mean all Cars are Toyota Corollas. Just because all apples are fruits, doesn’t mean all fruits are apples. Speaking of food, if we considered eating to be a method, it’s much better that it works with an abstract class of Food rather than any particular concrete food object type. If we could only eat one specific food, or even could only eat one specific type of food (such as cheese), this would severely impact my quality of life (especially since I’m a foodie). The fact that I can digest just about any food that’s safe for human consumption is quite preferable to me; abstract classes come in handy not just in the world of code, but also in real life. As I mentioned early on in the article, being able to translate real world objects and concepts into code is really a major key on the path to true mastery of Object Oriented Programming. After all, OOP is programming oriented towards real objects; the more you understand everything in the universe around us, the better you’ll be at implementing them in code.

On that note, I suggest trying to further develop our class hierarchy based on your understanding of vehicles in the real world. I have created a basic foundation (which you can modify all the way down to the core), but you should continue to build upon it to fully grasp the concepts of Object Oriented Programming. It’s my sincere wish that this article has helped you understand OOP. With that being said, if you just copy my code like a robot, you’ll be limited in terms of how much you’ll really learn. The path to mastery is truly a journey, and you need to keep digging deeper to figure out how deep the rabbit hole really goes. I had mentioned earlier that we can also create Boat and Airplane classes which inherit from the Vehicle class. Create your own Boat, Airplane, and Car classes, complete with fields and methods appropriate for each. You could even try to implement the Engine class (which was left empty, and could have been more appropriately called CarEngine) if you have an idea of how an engine should work. Sometimes, the best way to learn to swim is to jump in the water (with floaties of course), and such is certainly true of writing code. So go ahead – keep learning, keep growing, keep asking questions, keep causing bugs, keep getting frustrated, keep fixing bugs, keep getting excited, and keep making the magic happen with your code. If you complete an complete Vehicle class hierarchy based on your own understanding and research, you’ll learn much more than I can teach you within the context of an article. There’s no one correct way to complete the class hierarchy exercise; the important thing is that you focus your entire being into it and do the best you can.

Be the first to comment

Leave a Reply

Your email address will not be published.