Occasionally I'll come across comments about inheritance going "out of style" in enterprise application architecture, but I haven't come across a link to an article describing a competing theory. Also, is there a difference in implementation if the application is already built as opposed to starting from scratch? I gather this might have something to do with relying heavily on interfaces instead, but I'm not sure.
views:
191answers:
7What is the primary competing design pattern to concrete inheritance in application architecture?
I think you are refering to the Design Principle:
"Favour Composition over Inheritance."
This isn't so much an architecture issue as a nitty-gritty class design issue. Implementation inheritance has two areas of difficulty: the fragile base class problem and the static nature of inheritance relationships.
The classic alternative in this case is the decorator pattern of interface implementation with composition: the new object contains a reference to the lower-level object it wraps, and forwards calls to it, with perhaps some calls wrapped or replaced outright. A single wrapper class can have its instances wrap different underlying service implementations, and the wrapper is much less likely to be broken by the fragile base class problem because it has no access to protected members.
A very popular alternative to inheritance (as in subclassing) is object composition and delegation.
So instead of
public class B extends A implements I {
// now I have all the methods from A
}
you do
public class B implements I {
private I a;
// delegate all methods
public void methodOne(){
a.methodOne();
}
}
Composition is more flexible than subclassing:
- You can have more than one delegate (as opposed to only one superclass, at least in Java)
- It cleanly separates interface from implementation (whereas with a superclass, you get both its methods and their implementation, and even methods that are not in the interface)
- You can swap out delegates by configuration at runtime (whereas the superclass instance is compiled in). Dependency injection builds on this.
Allen Holub describes in this article how implementing an Interface is preferred over subclassing. though this was written in 2003, it is still on topic. funnily, there are a bunch of comments from 2009!
inheritance is not a style
it is a tool
so is composition
Whenever I read some blanket missive like this I think to myself:
Phillips screws are better than Flatheads.
Neither one are any good when you need a nail or a weld, and either or both are fine when you know what you're doing.
the difference between the two is stark and simple - "is-a" vs. "has-a" - and while composition can be used to simulate inheritance (with a lot of extra work) the converse is not generally true. This is not an argument against inheritance, nor is it an argument for composition.
The semantics of the model are far more important than the mechanism used to represent it. It would be silly to say "a reptile has an animal and uses delegation to expose its methods and properties", instead of "a reptile is a kind of animal", would it not? So why is doing the same thing to an object unnecessarily not just as silly?
inheritance is incredibly useful, and is fundamental to object-oriented programming. It is not going away until something better comes along, and I haven't published that yet ;-)
[let the flames begin!]
If you are using C++ then you should seriously consider using mixins (note: some other languages claim to support some form of mixins):
Wikipedia: http://en.wikipedia.org/wiki/Mixin
Dr. Dobbs: http://www.ddj.com/cpp/184404445.
More interesting is the "curiously recurring template pattern" (CRTP):
Wikipedia: http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern.
I see the CRTP as an application of mixins that is very useful.
Once you "get it" (this takes a while), you realise that mixins are very pwerful. They give you a method of code reuse that does not suffer the problems of reuse by inheritance, but is more flexible and efficient than using composition and delegation.
Interestingly, the CRTP allows you to simulate virtual function calls, removing the overheads (in time and space) of real virtual function calls where this language feature is not specifically required. Removing the virtual functions calls allows the compiler to provide better optimisations, leading to better performance.
The list of benefits just goes on and on... on the downside, it is syntactically ugly in C++, but you learn to live with that. Using macros to form the mixin chain can make the code far more readable.
In my view I see mixins as reusable snippets of code that can be used to build up a class. Typically they help you implement an interface, providing common implementations of methods. You end up feeling like you can just "go shopping" for the bits that make up your class and have very little "plumbing" to do to get the parts working together.