Before I get too far into the weeds of object-oriented programming (OOP), it might be useful to see the difference between OOP-style code and doing the same program in other programming paradigms.
I created a short program that does four things:
First, here’s the program using as much of a simple, monolithic style as Java will allow. You don’t have to type this program in unless you really want to.
So, lines 8-9 input the message, lines 12-14 reverse it, lines 17-21 camel-case it, and line 24 displays it. Don’t worry too much if you don’t understand the details of the camel-case part.
Next, I have coded the same program in a “functional” style. Functional style uses only functions with a few inputs and only one output each. The functions don’t share information with each other except through their inputs and outputs.
Again, there’s no sense typing up this version unless you want the practice. (It does work, though.)
Lines 1-9 are the same as the previous version, because it’s kind of hard to get input from the human in Java any other way.
But you can see on line 12, the message (in the variable msg) is passed in to
a function called
reverse, and the result is put back into msg, overwriting
the previous value. This is a bit more understandable.
And lines 21-27 are the
reverse() function itself. It’s the same code as
lines 12-14 of the previous assignment, but there’s a little extra setup to
name the function and name the parameter and also an extra line to “return” the
final result. Notice, though, that we get to call the input s instead of
having to care that it’s really called msg elsewhere. It’s a bit nice to be
able to call that variable whatever we want without caring what happens in
other parts of the program.
Line 15 is the
camelCase function call, and lines 29 through 36 are the
function definition. Notice that on line 29 we were free to call the parameter
s without caring about other parts of the program.
Is the variable in
main() really called
Is some other function already using a variable called
What variable is the return value going into?
It doesn’t matter. We can call it result or rev or whatever suits us.
Another nice thing about a functional style of programming is that since each function receives an input and returns an output, functions can be chained very compactly.
Here is the same functional version, but with the functions all nested inside each other.
You read line 8 from the inside out. The inner-most thing happens first:
keyboard.nextLine() is called. Once it’s done, it returns a String, which
we pass immediately to
Some programs are more difficult in a functional style, but when it works it’s really nice and clean-looking.
By the way, formulas in a spreadsheet program like Microsoft’s Excel, Apple’s Numbers or LibreOffice’s Calc are programmed in a functional style. This is a tricky way to code, as you know if you’ve ever struggled to get one right!
Graphics-processing shaders (like in OpenGL or Direct3D) are usually written in a functional style, too, and that makes them well-suited for parallel processing.
Okay, finally let’s do this same little program in an object-oriented style. We’ll use two files as usual: one containing our class/object, and one with the driver. These are the ones you should type in.
There’s something new in this one. On line 3 there’s an instance variable / field, just like you learned about in the previous exercise.
Notice that on line 6, there’s a method that stores a copy of the parameter s into a variable named message. Where is this message declared? It’s the field. We’ll look more at this in later chapters, so don’t worry too much about it for now.
Just remember for this code, any time that “message” is referenced, it’s the instance variable. All the other variables are “local”, which means they only exist inside the method in which they are defined.
So, here’s the code for the driver. Type this one in, too.
(There’s the output again so you don’t have to scroll up for it.)
This is very typical object-oriented code. Line 11 declares and instantiates
an object. Line 12 calls the
setMessage() method of that object, and passes
the message into it as a parameter. Then the next few changes happen inside
the object: the message gets reversed, then the message gets camel-cased.
Finally on line 17 of the driver we call the
getMessage() method of the
object, and it returns to us the modified String for printing.
Maybe you don’t like the object-oriented style. Maybe you think the monolithic version is better, or maybe the functional version.
You know what? I agree with you. Object-oriented programming isn’t a very good fit for a tiny program like this. OOP works best when the programs are large and complicated (like 10,000 lines of code or more).
Whenever I write a program to help me automate something annoying, I almost never code it in an object-oriented style if it’s going to be only 500 lines of code or less.
I write it in a monolithic style if it’s just going to be 10-50 lines long. I use functions when it’s 50-500 lines long, and I start out object-oriented if it’s going to be much bigger than that.
Unfortunately the rest of this book is going to be a little weird. I’m going to use the object-oriented style even for tiny 20-line programs. It’ll be gross. You might not like it. You might think “This program would be so much simpler if he would just….”
But I can’t teach you object-oriented programming using only nice huge 1,000 line perfect examples where OOP makes sense. (Well, I could, but this book would be about 800 pages longer and I wouldn’t have finished writing it yet!) Instead I have to teach you OOP using small silly example programs where the OOP feels weird and forced but the programs are small enough to understand.
Once you’re done with this book, you’re free to code for the rest of your life in a non-object-oriented way. But, if someone dumps a 20,000 (or two-million!) line program on you that uses OOP just to have any hope of preventing bugs, then you’ll have the tools to make sense of it.
“Learn Object-Oriented Java the Hard Way” is ©2015–2016 Graham Mitchell