"An abstraction denotes
the essential characteristics of an object that distinguish it from all
other kinds of object and thus provide crisply defined conceptual
boundaries, relative to the perspective of the viewer."
— Grady Booch
Abstraction basically does not require us to understand the specifics. For example, take a look at your monitor. Is it CRT? or LCD? what’s the resolution? how many buttons are there? How big is it? How bright is it? The answers to these questions will describe the specifics of the monitor. However, in the end, it just is a monitor. If you know the model and maker of the monitor, you will definitely find out the answers to all of the above questions. The idea that those models are just a “monitor” would be equivalent to what an “abstraction” of that monitor is. The monitor in front of you will be a specific model of what “monitor” (abstraction) is. Well, you need a maker and model for every monitor but the specifics can be abstracted.
From the coding perspective, abstraction is simply an interface which simplifies the functionalities of complex items in a simple way. With abstractions, you should be able to work on it without knowing any specifics of the item. From the testing perspective, think of a “black-box testing”. It is basically a test of an abstraction. You basically know what you are facing with, without the details.
In programming, by abstracting objects, our goals are to achieve the following 2 items:
Let me show you an example. Say we have a Dog class which can
eatDogFood like below:
Now there is a Cat class which can
eatCatFood like below:
One could make a use out of these classes in this fashion:
This works great until we have another animal, a
horse, then we have another one
pig, then another, and so on. Above if-else block can get really long and it is pretty tightly coupled.
There obviously is a better way to handle this through abstraction with composition. Instead of having these if-else block, we could create an Animal interface which handles eat functionality along with animal classes:
Then have the function pass in the object that is eating and our code can be as simple as:
Now our code is not only loosely coupled, it is simplified and much more organized. Also, our code does not require all these dependencies of different animal classes/modules.
You will notice that abstractions are used in a lot of different software principles because that is the nature of humans, we love to abstract things. We like to see things in an abstracted way because of the simplicity and easier understanding of an object.
An example of abstraction can be as simple as, a pen which dispenses ink when I write. How does it do that? No idea. I just need to know that a “pen” lets me write. “TV” is another example. We need to know how to turn it on and change channels but how it works inside TV is hidden to the users. Think of a “war”. It is an abstract idea since there are many different kinds of wars which have their own unique events and places. World War II is one of a specific example of a “war”. We know the details such as when, how, where and why it happened. It’s specific, not abstract. Abstraction can really be any objects you see around.
What about that bus I took this morning? Do you happen to know the technical implementation of the bus? how it moves through the engine and how they are all connected? Probably not. At most, you probably need to know that “I took a bus”. The “bus” itself is an abstraction. But as soon as I got out of the bus, I saw this beautiful Porche waiting right behind the bus. A “car” could be another abstraction of that specific Porche that was waiting behind the bus.
Now, we can raise a question, can “car” and “bus” be abstracted into a “transit”? Sure. Let’s say these abstractions are used in a software. When the software gets bigger and bigger, we may need to support “airplanes”, “trains”, or “cruises” etc. An abstracting these abstracted objects can be helpful to organize and simplify your code. However, it also can complicate the system. It can create a maze to find a functionality or behaviour. The complication is worst kind in code. So it is important to have a right balance. Remember our goal of abstraction? Code readability and simplicity!
“Abstraction > Complexity > Complicated”
Abstraction is almost always better than complexity but in my opinion, complexity is still better than complication. If abstracting creates a complication in your code, leave it the way complex.
If you think about it, you probably can abstract a lot of objects of little things like “round”, “dispenser”, “metal”, etc. Then have multiple of these abstractions to create an object such as “metal round dispenser”. Well, its abstracted to a nearly a thing. But it can be complicated to see what that thing really is. I now have to dig up the “round” features which have “dispenser” capabilities along with “metal” feature.
If above were the case, I would just abstract them to a general “Part” and name the class to what that “metal round dispenser” is and describe its appearances and behaviours as a method and variables in it. It’s much clearer and simpler this way.
If you are around my age, we have always been taught that there are 3 major principles of Object Oriented Programming:
aka “The PIE”. If I were to add the fourth one here, it will have to be the abstraction. “IPEA”?
Abstraction in OOP will hide all the unnecessary bits of an object to make objects stand out only the necessary bits. This eventually allows code much more distinct and obvious which leads to a simpler and efficient code.