𝗔𝗯𝘀𝘁𝗿𝗮𝗰𝘁𝗶𝗼𝗻 𝗶𝗻 𝗢𝗢𝗣: 𝗛𝗶𝗱𝗶𝗻𝗴 𝗖𝗼𝗺𝗽𝗹𝗲𝘅𝗶𝘁𝘆
You drive a car by pressing pedals and turning a wheel. You do not need to understand fuel injection or piston movement. The car hides these details from you. You only use a simple interface.
Software works the same way.
Think about sending an email. Your code likely looks like this:
emailService.send(email);
It looks simple. Behind the scenes, the system performs many tasks:
- Validates the address.
- Connects to an SMTP server.
- Authenticates the user.
- Builds the message.
- Handles retries.
- Logs errors.
You do not need to see these steps. You only care that the email sends.
If you expose every step, you create problems. Imagine if every developer had to manually call:
- connect()
- authenticate()
- buildMessage()
- sendMessage()
- disconnect()
This makes your code fragile. If you change your email provider, you must update every single place in your app. Your code becomes tightly coupled to the implementation.
Abstraction solves this.
Abstraction exposes what an object does. It hides how it does it. You show the user only what they need.
The user interacts with a stable interface. They do not care about your authentication logic or your retry strategy. Those details stay hidden.
Many people confuse Abstraction with Encapsulation. Here is the difference:
Encapsulation asks: Who can change the state of this object? It protects data.
Abstraction asks: What details should the user see? It hides complexity.
They work together to build better systems.
Next, we will discuss Inheritance. We will look at how to handle shared behavior without writing the same code twice.