Well, my thinking may not be correct, but here is how I think of this issue anyway.
I tend to think of abstract classes as the basis for designing/implementing specific functionality in terms of the "purpose and operation" of the object itself. I think of the abstract class as setting the "template" for defining "what an object is supposed to do".
I tend to think of the interface as the definition of how other classes call IN TO MY CLASS to use this classes functionality. In other words, to define the API in a manner of speaking.
What this separation buys you is this: Using abstract classes allows you to specify method names required to make the object do what the object is supposed to do.... more of an "internal to the object" point of view. The interface is used as a "how I can get this object to do what it does for ME" point of view.
Properly designed, you can use reference values of the interface type itself, NOT the class type. Thanks to
polymorphism, the interface type reference variable will hold a reference to any class that implements the interface and the only methods that the caller can call are those specified by the interface. That enhances looser coupling. The calling class can't get at any of the methods specified by the class hierarchy, only the ones specified in the interface.
My favorite example of this is a custom "logging" facility. You can design a set of classes that facilitate data logging functionality to the screen, to files, to a network resource, to an "in memory" container, anything you want. Above them you wou8ld create an interface that specifies all methods that allow logging of data.
So you might have three classes defined:
class ScreenLogger implements Logger { ........ }
class FileLogger implements Logger { ........ }
class NetLogger implements Logger { ........... }
That means that each of those logging classes must implement the methods specified by the interface in such a way that they perform the requested logging for that class type according to the "contract" specified in the interface.
Now, when you want to use a logger, define a reference variable as the interface type:
Logger logType;
From here, any place that calls methods on the reference logType
(example logType.logDate() or perhaps logType.logPacket() each of these methods would have to be specified in the interface and implemented by each of the logging classes!)
will work, no matter which actual logging class is currently held in logType. This happens because of the adherence to the interface specification. Using the interface in this manner gives no visibility into the other methods that exist in the class because the interface variable doesn't have them defined.
I hope this helps...
[ October 01, 2008: Message edited by: Bob Ruth ]