This week's book giveaway is in the General Computing forum. We're giving away four copies of Arduino in Action and have Martin Evans, Joshua Noble, and Jordan Hochenbaum on-line! See this thread for details.
There is a pattern (actually I don't know if pattern is the right term, perhaps "idiom") that I've ssen used a lot and which I've emulated a number of times.
Let's say that an application has an abstraction -- let's call it a "schmoo". The "pattern" I've seen is that an interface, Schmoo, is created that defines the behavior of all things schmoo. Then an abstract base class is defined, AbstractSchmoo, that implements some of the rote behaviors defined by Schmoo, as well as providing other useful methods needed by concrete schmoos such as ThisSchmoo, ThatSchmoo and TheOtherSchmoo. Within the application, all schmoo-like things are treated as a Schmoo.
I've used this idiom myself since it seems so, well, "tidy". In fact, IntelliJ (which I really like) continually advises me to use this pattern when you turn on the "advice" feature.
But it occured to me that if someone were to ask "Why define an interface at all? Why not just use the abstract class?" that I wouldn't have a really good answer. All schmoos extend AbstractSchmoo, so why not just rename it to Schmoo and jettison the interface?
Has anyone heard of or use this "pattern"? Is it a real pattern that has a name? Am I smoking crack and no one has ever heard of anything like this?
If you are familiar with this, how would you answer the "why the interface?" question? [ January 23, 2006: Message edited by: Bear Bibeault ]
I wouldn't call it a pattern, I don't think. In the JDK APIs it's often called an "adapter", but that's definitely not right. It's just a default implementation of the interface, for convenience sake.
Why do you use the interface? Because then you can test without dragging in the abstract class. You can use an auto-generated proxy implementation as a Mock object, as in EasyMock; or you can hand-code a mock object that gives better access to test-relevant data.
You also use it because there may be implementations you can't foresee which wouldn't want to use the abstract class's implementations (if they didn't, but extended it anyway, this is called a "Refused Bequest.") This is especially true if the abstract class has data members -- maybe some implementation won't want that data.
You also use it because maybe something wants to be a Schmoo and a JComponent at the same time. Only with the interface-based design is this possible.
Originally posted by Bear Bibeault: Has anyone heard of or use this "pattern"? Is it a real pattern that has a name? Am I smoking crack and no one has ever heard of anything like this? [ January 23, 2006: Message edited by: Bear Bibeault ]
Have you heard of the standard Java API? This practice seems to be used all over the place:
And that's just from the Collections API! You should look at Swing for more examples, and I'm sure there are plenty else where.
As for the reason, I'm not entirely sure. One potential reason is that you can implement multiple interfaces. But you can only extend one abstract class. So say you want to create a SchmooList class, you cannot extend both AbstractSchmoo and AbstractList. Instead, you would have to pick ONE of the default implementations to extend and implement the interface for the other one. This seems like a decent reason, but there may be others.
At the beginning of the year, I posted this in JavaRanch's "OO, Patterns, UML and Refactoring" forum: Java without interfaces. I had just read Dr. Dichotomy's (Eamonn McManus) Development Diary: Java API Design Guidelines, and had heartily agreed with all his major points until I came to Interfaces are overvalued: A type should only be an interface if you have a good reason for it to be [one]. Like some Java-based Martha Stewart, I had always thought that Interfaces are a good thing, but then I tried a thought experiment: what Java still be "Java" to me without interfaces? Or would the way I code have to dramatically change? Don't get me wrong. I'm not proposing that Java drop interfaces or that Java must prove it is consistent as code is accelerated to near the speed of light I just wondering if it would be life, Jim, but not as we know it.
In that thread, two things were mentioned that required interfaces and/or the ability to implement multiple interfaces: 1. Dynamic proxies require interfaces. I'm still not convinced that there isn't some way to get dynamic proxies into a interface-less Java, by hook or by crook... 2. Ilja Preuss mentioned the "Interface Segregation Principle", and that requires, or works most naturally with multiple inheritance of interfaces. I'm embarassed to say I've never designed an interface around that principle, although I found the article interesting and I'm still digesting it into the code I'm currently working with.
I still feel that one can go far (except for dynamic proxies) in Java by using abstract classes with all abstract methods in place of interfaces, and never missing mutiple inheritance of interfaces.
But getting back to the original "pattern" (I too wish it had a name): I think that it is still useful (with the interface at the top, or a heretical pure abstract class). Consider TableModel and AbstractTableModel (or most any of the Swing model examples). AbstractTableModel provides some boilerplate code for listener management by having a protected javax.swing.event.EventListenerList member. Now suppose you want to define a class that either implements more than one listener interfaces (or has an inner object for each listener interface in question) and you want to code this with a single shared EventListenerList for the object. (Recall that by design, you can store different types of listeners in the same EventListenerList.) If you use the abstract classes with their boilerplate code you will have mutiple EventListenerLists, unless you do this, which makes me queasy in the same way as those films where they change a monkey's brain with that of a man Maybe I wouldn't feel so sheepish if those abstract classes had a constructor that let you pass in a EventListenerList. That would make this trick kosher.
My take on this was the default class with do-nothing mehtods is there for "convenience" (as mentioned above) because the interface had a lot of methods and you might only want to provide functionality in one or two. Design principles like Interface Segregation (also mentioned above) and Single Responsibility tell us that if you need any part of a class or interface you should need all of it. This is obviously not the case (with my definition of convenience) so the original interface was probably poorly designed with methods that don't go together all that well.
If you find these in the Java libraries, use them because they really are convenient. If you find yourself writing interfaces that need default implementations like this, see if they shouldn't be broken up.
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Joined: Dec 06, 2001
Originally posted by Stan James: My take on this was the default class with do-nothing mehtods is there for "convenience" (as mentioned above) because the interface had a lot of methods and you might only want to provide functionality in one or two.
Bear is talking about an abstract class that implements some methods with meaningful code (i.e. not just "do-nothing methods"). I think you are confusing this with the adapters used for event handling (e.g. ContainerAdapter) that implement do-nothing methods for convenience since you don't often want to handle every possible event defined in the corresponding interface. On the contrary, the classes mentioned so far actually implement some methods with default behavior. Take a look at any of the AbstractXxx classes in Swing or the Collections Framework.
Joined: Jan 29, 2003
I was thinking of the *Adapter classes rather than the Abstract* They say things like: "The methods in this class are empty; this class is provided as a convenience for easily creating listeners by extending this class and overriding only the methods of interest."
You're right - I missed the OP bit about "AbstractSchmoo ... implements some of the rote behaviors defined by Schmoo, as well as providing other useful methods needed by concrete schmoos such as ThisSchmoo, ThatSchmoo and TheOtherSchmoo."
Look into the Template pattern in GoF: "Define the skeleton of an algorithm in an operation, deferring some steps to subclasses." This is very common in frameworks that take control of the flow of work and require or allow you to plug in custom behavior in certain spots by overriding methods.
It's also common but maybe a little more problematic to provide helper methods in a base class. I thought I was being very clever doing that a couple years ago and later realized the helper methods should have been in a separate class. Now people create subclasses of the abstract just to get the helpers, not because the class is really filling the role that the abstract implies. My bad.