views:

191

answers:

7

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.

+6  A: 

I think you are refering to the Design Principle:

"Favour Composition over Inheritance."

Mitch Wheat
A: 

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.

Jeffrey Hantin
+3  A: 

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.
Thilo
A: 

There's also Traits & Roles in Smalltalk & Perl. They let you reuse functionality. Check out this article.

mamboking
A: 

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!

akf
I always loved Allen Holub's attitude. Though he can be extreme, I have to say that following his advice has greatly improved my own code.
Joe M
+1  A: 

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!]

Steven A. Lowe
"while composition can be used to simulate inheritance (with a lot of extra work)": It is very little extra work, and that can be dealt with in tools. Same situation as generating getters/setters. Some languages have a delegate keyword, which makes composition a first-class-language construct, just as subclassing is with its "extends" keyword.
Thilo
@[Thilo]: URL please, that sounds interesting! But, taking a random (very small!) class from a recent project, I see 7 properties and 4 methods. Subclassing this would be ZERO extra lines of code. Composing and exposing via delegation would be AT LEAST 11 lines of code (more in most OOPLs). When the superclass method signature or property type changes (rare but it happens, esp. during development), composition requires me to manually fix it everywhere, while inheritance just picks it up automatically. Inheritance is fundamental; composition is a facade. Not the same, even with a magic wand.
Steven A. Lowe
Tool support: Eclipse has "generate delegate methods" for Java. Of course, it does not keep it in sync with "upstream" changes. But this would be equivalent to changing an interface definition. There could be an equal level of refactoring tool support (not sure if there is now).
Thilo
"Inheritance is fundamental, composition is a facade". That is just a language design decision. They could be given the same status. I don't think inheritance is as fundamental to OOP as, say, polymorphism and encapsulation.
Thilo
While we are at it, the existence of classes and interfaces in the first place is not really fundamental either (although I would not want to miss them for the tool support they enable in Java). JavaScript works fine without them.
Thilo
@[Thilo]: your last two comments are factually incorrect. See http://stackoverflow.com/questions/402984/main-concepts-in-oop. JavaScript follows a prototypes-and-delegation model, which is equivalent to classes and inheritance. Red herring.
Steven A. Lowe
Exactly my point. It uses prototypes and delegates instead of classes and inheritence. Goes to show that classes and inheritence are not fundamental to OOP.
Thilo
This is entering flame-war country, but note that you can change the prototype at runtime, which is not possible with a superclass. So maybe delegation is superior to subclassing ;-)
Thilo
@Steven - regarding your comments about "AT LEAST 11 lines of code". I would challenge you to decide which approach is better from a design point of view, not a coding point of view. Just because you can misuse a language feature to minimise lines of code, it doesn't mean it's the right approach. In C++ I would write the delegation code once as a mixin and then mix it into my final class as required - adding the mixin to the mixin chain is less than one line of code. Composition and delegation does not imply a heap of repetitious plumbing code.
Daniel Paull
@[Daniel Paull]: "decide which approach is better from a design point of view" - that is exactly the point I'm trying to make in the original post. And if I understand your C++ example correctly, your mixin takes advantage of C++'s multiple inheritance, does it not? ;-)
Steven A. Lowe
@[Thilo]: There are two OOP models, semantically equivalent; though I do agree that prototype/delegation is a superior model, that wasn't the original question ;-)
Steven A. Lowe
@Steven - no it does not.
Daniel Paull
@Steven - perhaps to clarify, the mixins form a chain of single inheritance. The interesting thing is that inheritance is used as a means to an end - purely technique with no higher level semantic in terms of what it represents in the object model. So, if my class inherits FooMixin<Base>, it does not represent an is-a from a domain modelling, nor a substitutability point of view.
Daniel Paull
@[Daniel Paull]: so you couldn't do what you're doing without inheritance then - pardon my LOL ;-)
Steven A. Lowe
@Steven - you said in your post that inheritance represents an "is-a" relationship between the super and sub classes - this is not true in the case of mixins. Would you agree? The point of my original comment was to refute your bold comment of "AT LEAST 11 lines of code", which seems be your gripe against the use of composition. Would you agree that mixins remove this barrier to adopting composition for code reuse over inheritance?
Daniel Paull
@[Daniel Paull]: mixins may be a special case, I'd have to see how you're using them to decide if "is-a" is implied or not. I've used mixins in other languages and in almost all cases the generalization/specialization relationship ("is-a") was applicable. My bold comment was in reference to _most_ languages (for example, C#) so your exceptional use in C++ is not quite a refutation but it is an example of how to do this more efficiently in that language. No, I do not agree that mixins remove a barrier because mixins *still* require inheritance - just a more granular form of it.
Steven A. Lowe
Given that a mixin should be designed so that it can be used multiple times to build up a class (example, a mixin to help add a "child" in a tree structure maybe used twice if the node has two children) shows that is-a is not the relationship. Imagine looking at the inheritance heirachy: MyNode is-a ChildNodeMixin is-a ChildNodeMixin is-a <next mixin here>. Makes no sense at all... Mixins are merely a private implementation detail for the concrete class.
Daniel Paull
@[Danial Paull]: OK, I think I understand what you are saying now, and I agree; this form of mixin usage is a combination of inheritance and composition, and it is very very powerful. Perhaps even more powerful than we can possibly imagine (to mis-quote ObiWan Kenobi) ;-)
Steven A. Lowe
A: 

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.

Daniel Paull