Reflection on OOP: Inheritance or Generalization
As software engineers, we most likely have learned the three key characteristics of object oriented programming: inheritance, encapsulation, and polymorphism. Over the years I study and practice OOP, I realized that inheritance is out of date and arguably misleading, therefore should be replaced.
In OOP, inheritance refers to a relationship between two classes in which a subclass inherits the properties and methods of its super class. The term inheritance is not really a good one because it implies a transfer of something between entities, like assets from a parent to a child.
Lost VMs or Containers? Too Many Consoles? Too Slow GUI? Time to learn how to "Google" and manage your VMware and clouds in a fast and secure HTML5 App.
When used in the context of OOP, the inheritance refers to essentially a logical relationship of two classes in which a subclass is extended from a super class. Due to this very reason, many experts (I am in this camp as well) prefer to use generalization over inheritance. As you can see, generalization captures the logical relationship but refers to the opposite direction to inheritance. For the same direction as inheritance, you can use extension. It explains in language like Java, you see “extends” but not “inherits” while declaring a new subclass. Alternatively, you can also use specialization for extension. Strictly speaking, specialization is better than extension here.
The terminology difference reflects difference at concept level, which may seem subtle, but very important for understanding the essence of OOP, and in the end for modeling and designing a software system.
Interestingly, different groups of developers see the same relationship differently while practicing OO. The API designers see more generalization; the API users see more the extension. As API designers, you have to abstract the classes into hierarchy so as to remove duplicated code and improve code re-use. For example, if you have two similar or same methods in two different subclasses, you want to pull them into super class as one single method. The more you move up to the super classes, the less your code base and the better code re-use. Along the way you can create new super classes if they don’t exist yet. But remember, generalization is not compress process. You must make sense of a new super class, meaning it must be a meaningful type. A rule of thumb is whether you can easily name the super class – if not, it’s probably not meaningful.
As API users, you already have the existing class hierarchy there. What concerns you is how to leverage and re-use the code in the API implementation. One of the common ways to use OO APIs is to extend (inherit) the existing classes. In other word, you create new subclasses of existing classes. What you see is the extension (or, inheritance).
Another common way to use API is via composition. It means you create new classes that include instances of existing classes. In general, composition is preferred over the extension because composition does not break the encapsulation. Think about this, if you create a subtype of an existing class, you gain access to the public/protected properties, meaning you can change them as well.
In summary, the inheritance is a characteristic that is out of date and should be replaced by generalization. Generalization really means more for API designers than for majority API users.