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!
Thank you for your wonderful article.
I agree with most of your description, but I disagree with the conclusion that “Object Oriented abstraction is naturally expressed by inheritance”.
First of all the most important part of the OOP is the encapsulation which means that only the Object controls its internal attributes.
Regarding inheritance, I think that most of the mistakes and the wrong design of developers are besed of their eager to use the inheritance. As in real life part of the inheritance is good but in most of the cases you wish you can save part / all the inheritance (The things that your spouse inherited :).
Inheritance meas a relation of A is a B while what you probably want to achieve is A have some capabilities of B. A composition is almost always a better choice than inheritance.
The conepts of ‘Abstraction’, ‘Generalization’ and ‘Specialization’ are much older and broader than explained here in the context of OOAD. The explanation of these terms are too OOAD oriented but their validity is more pervasive and potent. I have arrived at a definition of ‘Abstraction’ and I will present it after knowing published definitions the member of this group may be familiar with.
I am not sure of relative ranking of key principles of OOAD but I tend to agee with Shlomo that encapsulation (or integral unity and defined self-sufficiency) of object is a potent principle for analysis and design of systems (not only software but the non-material nature of software multiplies the benefits).
I find that Class hierarchy and Compostion relations are used in the same context here and in many publications but their nature is fundamentally different. I believe that the benefits of one cannot be compared to the other. Let’s identify a widely-accepted publication on this aspect. Based on that I wish to present my views.
Mail to me directly (firstname.lastname@example.org) to see the documents / ppts I have on these topics.
Pingback: Antifragile Software Design: Abstraction and the Barbell Strategy | Effective Software Design