"Hello, Amigo! Today I'm going to open a new and interesting world to your view. I'm talking about Object-Oriented Programming (OOP). You've already gotten to know classes and objects. Today you're going to learn more about them, much more."
We'll start with the four pillars of OOP. They are abstraction, encapsulation, inheritance, and polymorphism. (There used to be three, but abstraction was added later)
A good example of abstraction in real life is job descriptions at a company. A job title is one thing, but its duties are an entirely different matter.
Imagine you're creating the org chart for your future company. You might divide up the duties of a secretary, spreading them out over several other positions. You might split the CEO's job into several separate positions: chief financial officer, chief technology officer, chief marketing officer, chief human resources officer. Or you could combine the positions of office manager and recruiter into one.
Suppose you come up with names for positions at your company, and then you "dish out" the responsibilities for these positions. That's abstraction - splitting something large and monolithic into several small parts.
From a programmer's perspective, abstraction is properly dividing a program into objects.
A large program can usually be represented as interacting objects in any of a dozen different ways. Abstraction lets you pick out an object's main characteristics and omit anything less important.
Abstraction is like a military strategy. If you choose the wrong strategy, no ingenious tactics will save the day.
Encapsulation is intended to improve the interaction between objects by simplifying them.
The best way to simplify something is to hide anything complicated from those who don't need to know about it. For example, if you sat down behind the pilot controls of a Boeing jet, it would take a long time to understand how they work:
On the other hand, everything looks simpler to the passengers on the plane: they buy a ticket and board the plane, which then takes off and lands. You can easily fly from continent to continent, knowing only how to «buy a ticket» and «board a plane». We do not see any of the complexity related to preparing the plane for flight, take off, landing, and various potential emergency situations. And we've made no mention of satellite navigation, autopilot, and air traffic control centers. This simplifies our life.
In terms of programming, encapsulation is «hiding the implementation». I like that definition. Our class can contain hundreds of methods and implement highly complex behavior in various situations. But we can hide all its methods from prying eyes (by marking them «private»), leaving only two or three methods for interaction with other classes (by marking them «public»). Then all the other classes in our program will only see—and call—these few methods on this class. All of the complexity of the class will be hidden inside, just as the cockpit is kept from the view of happy passengers.
Inheritance is a concept in programming and real life. In programming, inheritance is a special relationship between two classes. But inheritance in real life is far more interesting.
If we need to create something in real life, we have two options:
1) make what we need from scratch, and spend a lot of time and effort doing it.
2) make what we need using things that already exists.
The best strategy is this: We take an existing good solution, rework and tweak it to meet our needs, and then use it.
Consider, human evolution. If we trace their beginning back to the beginning of life on the planet, we see that billions of years have passed. But if we think of humans as starting from monkeys, then only a couple million years have passed. Creating something from scratch takes longer. Much longer.
Similarly, in programming we can create one class based on another. The new class becomes a descendant (heir) of an existing class. This is super helpful when you already have a class that contains 80-90% of the needed data and methods. We simply declare a suitable class as the parent of our new class. All of the parent class's data and methods automatically become part of the new class. Convenient, right?
Polymorphism is programming concept that describes the situation where different implementations are hidden behind the same interface. To find an analog in real life, we can look to the process of driving a car.
If a person can drive a truck, then he or she could also be put behind the wheel of an ambulance or a sports car. A person can drive a car regardless of what kind of car it is, because they all have the same control interface: a steering wheel, pedals, and a gearshif. Cars are organized differently inside, but they all share the same control interface.
Return to programming, polymorphism lets us interact with objects of different classes (usually with a common ancestor) in the same way. The significance of this can't be overemphasized. It becomes more important as a program grows larger.
OOP is principles. Programming laws. Each of them restricts us in some way, but in return provides huge advantages as programs grow large. The four principles of OOP are like the four legs of a chair. If you take even one of them away, the entire system becomes unstable.