The Misconception of Object-Oriented Programming
When we think about object-oriented programming, we often relate it to real-world objects. The problem is this: associating object-oriented programming with tangible real-world things doesn’t work in 80% of cases, and this brings more difficulties than clarity for beginners.
Back in 1996, when I started programming in Delphi 4, its biggest competitor was Visual Basic, but Delphi was OBJECT-ORIENTED. If I had stopped at that programming course, I still wouldn't have known what this famous object-oriented programming was, and neither would the course instructor.
I worked at various companies and on commercial software projects in Delphi that were far from truly using object-oriented programming. Most Delphi programmers I met thought object-oriented programming was about dragging a button onto a screen, double-clicking it, and creating a function for that button, for example.
So, let’s talk about what object-oriented programming REALLY is.
First, look at the image below and tell me what you see.
Obviously, you see three cars: a pickup truck, an F1 car, and an SUV. The important question is: if these cars are so different, how do you know they are all cars? What makes a car a car and not a table or a piano?
There’s a concept of what a car is that’s already ingrained in your mind. A car IS LIKE THIS and SERVES THIS PURPOSE. In object-oriented programming, this concept that defines what a car is called a CLASS: it’s the definition of WHAT a certain object is. The car you touch, the one you drive from point A to point B, is what we call an OBJECT. It’s the materialized concept. This materialized concept is technically called an INSTANCE. That’s why you’ll sometimes read that an object is an instance of a class. Always translate this as: the object you touch is a concept that has been materialized.
Defining a Car: Attributes and the Blueprint of a Class
So, imagine you want to build a car from scratch. You’d take the car’s blueprint, a plan, and build that car. This blueprint is the Class; it defines WHAT the car is and HOW IT WORKS.
Let’s describe WHAT a car is. A car:
- Has a chassis
- Has an engine
- Has wheels and tires
- Has a steering wheel
- Has a gear shifter
- Has a driver’s seat
- Has an accelerator
- Has a brake
Maybe I didn’t list everything that defines a car because I forgot something, but let’s agree that not every car has a body, headlights, a clutch pedal, doors, mirrors, seat belts, or air conditioning, yet it’s still a car. Can a golf cart not be classified as a car? What about an electric car? Or a car from the 1920s? We’ll come back to this later, but there’s a basic concept of what a car is, and there are specific concepts for specific cars. Our basic class with attributes looks like this:
// Class
public class Car {
// Attributes
Chassis chassis;
Engine engine;
Wheel[] wheels;
SteeringWheel steeringWheel;
GearShifter gearShifter;
DriverSeat driverSeat;
Accelerator accelerator;
Brake brake;
}
Notice that the car’s attributes are also names of other classes. Also note that we didn’t describe what the car DOES, only what it HAS. We call what it has ATTRIBUTES, and some of these attributes can also be broken down into multiple attributes. For example, there are thousands of different types and models of engines, each with distinct attributes.
What a Car Does: Exploring Methods and Behaviors
Now, let’s talk briefly about what a car DOES. A car:
- Accommodates at least one driver
- Can be turned on or off
- Moves forward or backward when the driver presses the accelerator
- The gear shifter changes at least whether the car moves forward or backward
- Changes direction to the left or right when the steering wheel is turned left or right
Just as I might have forgotten something a car DOES, there are other things I didn’t list because not every car DOES them, like sounding a warning when the horn is pressed or lighting up when the headlights are turned on. So, our class with its methods looks like this:
public class Car {
// Attributes hidden
/*
* Methods
*
* The internal implementation is not relevant now
*/
public void acommodateDriver(Driver driver) {}
public void turnOn() {}
public void turnOff() {}
public void accelerate() {}
public void changeGear(Gear gear) {}
public void turnLeft(double degrees) {}
public void turnRight(double degrees) {}
}
What the car DOES, or the car’s BEHAVIOR, is called a METHOD or FUNCTION. A method or function is CALLED or INVOKED and can CALL other METHODS.
Imagine everything that happens when we call the accelerate method: the accelerate method activates the engine, which, depending on the gear position, will turn gears that, in turn, rotate a shaft, which will turn the wheels in a certain direction, making the car move forward or backward.
Abstraction and Encapsulation: Simplifying the Complex
When stepping on the accelerator, a person doesn’t need to understand the entire vehicle’s operating mechanism, but they expect the car to move. This is called ABSTRACTION. You don’t need to know a method’s implementation, but you know the result it will produce—and when it’s not working as it should.
Now imagine that to operate a car, you had to manually handle various cables, gears, and flammable fluids. Besides making the car’s operation much more complex, it would also be much more dangerous. The driver would be far more susceptible to cuts, burns, or operational errors. Instead, we simplify the process through an accelerator. The accelerator encapsulates the engine’s operation. This is called ENCAPSULATION. Encapsulation is the use of a safe and unique way to manipulate the object. Instead of handling the engine, the driver operates the accelerator.
So far, we’ve introduced some concepts. If you don’t CLEARLY remember a particular concept, go back a few paragraphs, reread, research, ask an AI for an explanation, but seriously, understanding these concepts is very important. So let’s list them:
- Class
- Object or Instance
- Attribute
- Method or Function
- Abstraction
- Encapsulation
Inheritance: How F1 Cars, Pickups, and SUVs Share a Common Base
Returning to the beginning of this post, we presented three very different cars: an F1 car, a pickup truck, and an SUV. We saw that in the basic concept common to these cars, several attributes and methods weren’t listed because not all cars have those attributes. However, we know that some cars do, and you might have wondered what to do in that case. The answer has a simple name, the one most remembered when we talk about object-oriented programming: INHERITANCE.
An F1 car inherits the attributes and methods of a base car. Similarly, a pickup truck and an SUV also inherit from the base car. But let’s talk about what makes these cars unique.
F1 car, among other characteristics:
- Accommodates only the driver
- Has a high-performance engine
- Has aerodynamic features like a spoiler and front wing
- Has a removable steering wheel
- Has no doors
- Has no ignition key
- Is lightweight
- Has tires and suspension for flat asphalt
public class F1 extends Car {
HighPerformanceEngine engine;
Airfoil airfoil;
FrontSpoiler frontSpoiler;
RemovableSteeringWheel steeringWheel;
WeightReductionKit weightReductionKit;
SpeedSuspension[] suspension;
HighPerformanceTires[] tires;
}
In Java, when we use the keyword extends, we’re defining that the class inherits the attributes and methods of another class. In the case of the F1 class, it inherits from the Car class.
Notice that several attributes were added, but the engine, steering wheel, and tire attributes were replaced by other classes. Thus, our F1 car will have all the attributes of a regular car, additional attributes, and different attributes.
Similarly, a pickup truck, among other characteristics:
- Has a cargo bed
- Has reinforced suspension and tires suitable for carrying weight and traveling on various terrains
- Usually has doors
- Usually accommodates the driver plus 1 to 4 passengers
- Has headlights
- Has a horn
public class PickupTruck extends Car {
CargoBed cargoBed;
HeavyDutyEngine engine;
HeavyDutySuspension[] suspensions;
AllTerrainTires[] tires;
Door[] doors;
PassengerSeat[] passengerSeats;
Light[] lights;
Horn horn;
}
SUV, among other characteristics:
- Accommodates at least 3 passengers besides the driver
- Has tires and suspension suitable for carrying passenger weight on mostly urban and highway routes
- Has headlights
- Has a horn
- Has comfortable seats
- Has ample interior space
public class SUV extends Car {
UrbanEngine engine;
UrbanSuspension[] suspensions;
UrbanTires[] tires;
Door[] doors;
DriverComfortSeat driverSeat;
PassengerComfortSeat[] passengerSeats;
ComfortInternalLayout comfortInternalLayout;
Light[] lights;
Horn horn;
}
If you’re not convinced, look below at what the SUV class would look like if we had to reimplement all the attributes and properties of the Car class:
public class SUV {
Chassis chassis;
UrbanEngine engine;
UrbanSuspension[] suspensions;
UrbanTires[] tires;
SteeringWheel steeringWheel;
Door[] doors;
DriverComfortSeat driverSeat;
PassengerComfortSeat[] passengerSeats;
ComfortInternalLayout comfortInternalLayout;
GearShifter gearShifter;
Accelerator accelerator;
Brake brake;
Light[] lights;
Horn horn;
public void accommodateDriver(Driver driver) {}
public void turnOn() {}
public void turnOff() {}
public void accelerate() {}
public void changeGear(Gear gear) {}
public void turnLeft(double degrees) {}
public void turnRight(double degrees) {}
/*
Possibly, more specific methods.
*/
}
Besides writing more code for the SUV class, we’d also have to duplicate that same code for the F1 and PickupTruck classes. In addition to code duplication, we’d also face increased difficulty in keeping this code cohesive, as we’d need the exact same code in at least three different classes.
The Limits of Inheritance: A Glimpse at Future Challenges
But if you’ve made it this far and are excited about using inheritance for your classes, I have some bad news for you. Take a look at the image below and tell me what you see.
Now we have a bicycle, a speedboat, and an electric car. All three are vehicles, and they all have things in common with regular cars, but they also have very distinct features. Inheritance in this case can bring excessive complexity and significant difficulty in categorizing all these objects. What can we do to solve this? That will be the topic of our next post, where we’ll continue teaching the basic concepts of object-oriented programming.
Leave your comments, suggestions, and questions below. I’ll see you in the next post.
Originally posted in my blog
Top comments (0)