Sunday, April 11, 2010

Why extends is evil

Why extends is evil
Improve your code by replacing concrete base classes with interfaces

By Allen Holub, JavaWorld.com, 08/01/03


http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html



I once attended a Java user group meeting where James Gosling (Java's inventor) was the featured speaker. During the memorable Q&A session, someone asked him: "If you could do Java over again, what would you change?" "I'd leave out classes," he replied. After the laughter died down, he explained that the real problem wasn't classes per se, but rather implementation inheritance (the extends relationship). Interface inheritance (the implements relationship) is preferable. You should avoid implementation inheritance whenever possible.

Losing flexibility
locks you into specific implementations, making down-the-line changes unnecessarily difficult.

coupling—the undesirable reliance of one part of a program on another part
"the fragile base-class problem" - Base classes are considered fragile because you can modify a base class in a seemingly safe way, but this new behavior, when inherited by the derived classes, might cause the derived classes to malfunction. You can't tell whether a base-class change is safe simply by examining the base class's methods in isolation; you must look at (and test) all derived classes as well. Moreover, you must check all code that uses both base-class and derived-class objects too, since this code might also be broken by the new behavior. A simple change to a key base class can render an entire program inoperable.
A better solution to the base-class issue is encapsulating the data structure instead of using inheritance.

Frameworks
an entire class framework that depends on derivation-based customization is brittle in the extreme

most of the Agile development methodologies (such as Crystal and extreme programming) simply won't work unless the code is written in the abstract.

If you examine the Gang of Four patterns closely, you'll see that many of them provide ways to eliminate implementation inheritance in favor of interface inheritance, and that's a common characteristic of most patterns. The significant fact is the one we started with: patterns are discovered, not invented. Patterns emerge when you look at well-written, easily maintainable working code. It's telling that so much of this well-written, easily maintainable code avoids implementation inheritance at all cost.