Programming is an exercise in abstraction. If a program is intended
to solve some problem, we must first be able to model this problem in an
abstract way, in order to express it in a programming language. Only
after the problem is modeled the solution can be built.
An algorithm can be seen as an abstract solution for a category of
problems. For example, the same sorting algorithms can be used to sort
anything: numbers, names or dates.
Thus, we can talk about levels of abstraction: In the first level, we
have the problem of sorting a list of values, and we need to abstract
this problem in order to write a solution (a program) for it. In a
higher level of abstraction, we are able to understand that the solution
is independent of the type of values being sorted, and then we can
create a sorting algorithm. When we create an algorithm, we are
generalizing the solution.
Design Patterns are another example of abstractions. In this case,
experienced software developers were able to identify recurring designs
in the systems they have built, express these designs in an abstract
way, and classify them according to the scenarios in which they should
be used. When a programmer decides to apply a pattern, he needs to adapt
the abstract design to the entities in his specific system. When we use
a design pattern, we are specializing an abstract design.
Therefore, the logic of abstraction can be used in both directions:
- Generalization: Creating a more abstract solution by ignoring details.
- Specialization: Creating a less abstract solution by adding details.
In object-oriented programming, abstraction is naturally expressed by
inheritance. In a well-structured class hierarchy, each superclass is a
generalization of its subclasses, and each subclass is a specialization
of its superclass.
Sometimes we start with a set of concrete classes and then we
understand that they have something in common, despite their
differences. In this case we abstract their properties, preserving the
shared ones and removing the specific ones, and the result is a
superclass that generalizes all the previous classes.
In other situations we start with a single concrete class and then
understand that there are several possible ways to extend its
functionality. In this case we specialize the initial class by creating
new concrete subclasses, each with its own properties and behavior, but
all of them sharing the functionality defined in the superclass.
Without a mechanism such as inheritance we would be severely limited
in our capacity to model a problem and its solution. Programming
languages without inheritance lack expressive power.
Accordingly, programmers that don’t know how to make good use of
inheritance are less effective. Invest your time in mastering the
correct usage of abstraction, and you will get very concrete quality
improvements!