The rise of modern high-level object oriented programming languages (e.g., Java, C#, Swift) brought with it the enforcement of single-parent hierarchy. This was the right path. And as we’ll see, when it comes to inheritance a phylogenetic approach is often best.
A class defines properties and attributes individuals have in common, i.e. it serves to classify such individuals as belonging to specific group. In terms of software architecture, one could make the argument—against single-parent inheritance—that a complex object might need to fit the classification of two groups and thus perform tasks from both classes.
For the sake of argument, let’s set aside the (possibly unmaintainable) implications of such an approach and focus on the original argument. Because in a single-parent hierarchy it’s still possible for an object to fit the classification of two or more kinds: their direct parent and their parent’s parent…and their parent, and so on. It’s a matter of a good ground-up hierarchy design to be able to discern which methods are required to have a base implementation (from an abstract class), and which methods only need to have its capabilities as a group publicly known (from their interface definition).
I like to use the example of a phylogenetic tree to explain what a good hierarchical framework looks like. Our starting point is the last universal ancestor of the tree of life.
From there, emerged three life domains: Archaea, Bacteria, and Eukarya. These domain descriptions strictly classify members in such a way that the member of one domain cannot belong to any of the other two.
As we traverse the tree, we find this strict description/classification happening at all ranks throughout the hierarchy (Kingdom, Phylum, Class, Order, Family, Genus, Species) and so should each of our framework’s subtrees. It’s up to the architect to capture which properties best differentiate one subtree from the others. For instance, the Eukarya domain denotes an organism consisting of eukaryotic cells.
Perhaps the reader will notice that all these classes are abstract. That is, they cannot be directly instantiated. There is solid reasoning behind this; there is no such thing as pure animal. An animal must belong to its respective phyla, class, et al.
Now let’s jump to the species level and take a closer look at a random one: Leptonycteris nivalis. If we were to have one of this bat species as a pet, we would most likely name it. In the same manner, an instance of a class is named and, from here, it can be inferred that, a species type of class must be able to be instantiated.
Now, as we all know, bats are not birds. But bats fly and so do birds. Is our classification system flawed? Well, no. We just need to find out the common ancestor within a given subtree to all species that fly and specify that as a capability. In this case, all members of the Order Chiroptera fly.
This same Flies interface may be re-used in all hierarchical sub-trees which contain a flying species and, in the same manner, provide a common implementation for all applicable subtrees that would perform the action in a similar fashion.
I hope you have found this explanation of the Phylogenetic Approach helpful. Got a question about this approach (or any other mobile strategy question)? Then give us a call! We’d love to hear from you.
Software Architect at Propelics