Object Oriented Interfaces
January 14, 2005 7:53 AM Subscribe
I'm trying to understand the OOP concept of an Interface. [More inside.]
I understand classes and inheritance, but I have a tough time with Interfaces. I get that all classes that implement and interface must define the interface's methods, and I get the idea that once this is done, multiple classes can be manipulated using the same interface. But I feel shaky about the concept. I get it and then I lose it. And many of the books I read focus much more on classes than interfaces. Yet I know interfaces are really important and useful in design patterns.
I'm looking for CLEAR explanations, examples of how they are useful, analogies and resources (books, links with clear explanations). I have programmed in C++ (a little), Java, Actionscript and PHP, but I'm entirely self-taught.
I understand classes and inheritance, but I have a tough time with Interfaces. I get that all classes that implement and interface must define the interface's methods, and I get the idea that once this is done, multiple classes can be manipulated using the same interface. But I feel shaky about the concept. I get it and then I lose it. And many of the books I read focus much more on classes than interfaces. Yet I know interfaces are really important and useful in design patterns.
I'm looking for CLEAR explanations, examples of how they are useful, analogies and resources (books, links with clear explanations). I have programmed in C++ (a little), Java, Actionscript and PHP, but I'm entirely self-taught.
Response by poster: Sorry. What is "Java's Comparable"? My Java experience is a couple of years rusty.
posted by grumblebee at 8:21 AM on January 14, 2005
posted by grumblebee at 8:21 AM on January 14, 2005
Interfaces are a contract. Any class that uses an interface must provide the code for the abstracted methods in the interface, otherwise you'll get a compiler error.
So in interfaces, you will generally see blank methods (C#- "public void doIt();" and when you write a class that uses that interface, you must actually flesh out and code doIt().
posted by xmutex at 8:28 AM on January 14, 2005
So in interfaces, you will generally see blank methods (C#- "public void doIt();" and when you write a class that uses that interface, you must actually flesh out and code doIt().
posted by xmutex at 8:28 AM on January 14, 2005
I think you can think of an interface as a base class for which every method must be over-ridden by its inheritors.
posted by callmejay at 8:36 AM on January 14, 2005
posted by callmejay at 8:36 AM on January 14, 2005
When learning Java I found it useful to think of interfaces as different hats. A person can wear many hats just as a class can have many interfaces. Eat hat signifies a different role just as different interfaces do. I can be class A doing the things that a class A does, but I may also be Comparable to other objects or perhaps I am Clonable and therefore easy to make a copy of.
posted by pookzilla at 8:45 AM on January 14, 2005
posted by pookzilla at 8:45 AM on January 14, 2005
I thought interfaces weren't necessarily an OOP concept, in that there needn't be an inheritance relationship between objects that fulfill the same interface (and inheritance is a way, but not the only or most flexible way, of announcing that you fulfill an interface).
here are two Python-oriented discussions of interfaces.
What pookzilla mentions is reminiscent of (my very limited understanding of) the way classes work in Haskell.
posted by kenko at 8:55 AM on January 14, 2005
here are two Python-oriented discussions of interfaces.
What pookzilla mentions is reminiscent of (my very limited understanding of) the way classes work in Haskell.
posted by kenko at 8:55 AM on January 14, 2005
Eat hat? Sorry about that. Each hat. I'm very hungry.
posted by pookzilla at 8:56 AM on January 14, 2005
posted by pookzilla at 8:56 AM on January 14, 2005
This any help? I thought it was quite a good explanation...
posted by normy at 8:57 AM on January 14, 2005
posted by normy at 8:57 AM on January 14, 2005
Interfaces are an alternative to multiple inheritence.
C++-style multiple inheritance can get you into trouble with conflicting implementations with the same method signature. Interfaces don't have this problem, because they don't specify an implementation.
Other than that, all you're saying is "this class I'm writing ought to support functionalty X, as defined by interface X(I), and here's how to do it, which may or may not be the same as how you thought it was initially supposed to be done."
Some good discussion about interfaces and implementations.
posted by Caviar at 9:10 AM on January 14, 2005
C++-style multiple inheritance can get you into trouble with conflicting implementations with the same method signature. Interfaces don't have this problem, because they don't specify an implementation.
Other than that, all you're saying is "this class I'm writing ought to support functionalty X, as defined by interface X(I), and here's how to do it, which may or may not be the same as how you thought it was initially supposed to be done."
Some good discussion about interfaces and implementations.
posted by Caviar at 9:10 AM on January 14, 2005
Extending xmutex's description, Interfaces not only enforce a contract, but they also provide a way reveal an object's programming interface without revealing its implementing class.
Understanding the AbstractFactory pattern will take you a long way to understanding Interfaces. Better yet, read the while book.
Also, if you're asking in the context of learning Java, I highly recommend Joshua Bloch's Effective Java. Item 34 is very illuminating.
On preview, Interfaces are very OOP; they're an excellent means to support polymorphism.
On double preview, I am a huge nerd.
posted by Loser at 9:11 AM on January 14, 2005
Understanding the AbstractFactory pattern will take you a long way to understanding Interfaces. Better yet, read the while book.
Also, if you're asking in the context of learning Java, I highly recommend Joshua Bloch's Effective Java. Item 34 is very illuminating.
On preview, Interfaces are very OOP; they're an excellent means to support polymorphism.
On double preview, I am a huge nerd.
posted by Loser at 9:11 AM on January 14, 2005
Response by poster: Thanks for the help so far. I will check out the links as soon as I get time.
Almost every book I read likens interfaces to contracts, but that's not good enough for me to understand that. I get that classes that use an interface are "contractually" bound to define the interface's methods. I don't get (in a deep sense, though I can think of a couple of examples) why you would want to set up such a contract.
I'm reading a book on design patterns right now that suggests you should avoid inheritance whenever possible and use interfaces instead. But they don't go deep enough into the theory behind this.
posted by grumblebee at 9:27 AM on January 14, 2005
Almost every book I read likens interfaces to contracts, but that's not good enough for me to understand that. I get that classes that use an interface are "contractually" bound to define the interface's methods. I don't get (in a deep sense, though I can think of a couple of examples) why you would want to set up such a contract.
I'm reading a book on design patterns right now that suggests you should avoid inheritance whenever possible and use interfaces instead. But they don't go deep enough into the theory behind this.
posted by grumblebee at 9:27 AM on January 14, 2005
think of interfaces as a way of defining the "type" of a class. an interface is a spec that something needs to implement if it's going to work with another piece of code. it does the same kinds of jobs as any other nicely defined specification (like a library API, in a non-OO language for example) in a programming language - lets you define what is needed, and where.
inheritance is a way of building/extending code.
unfortunately, the separation isn't clean because you can use a class in a specification instead of an interface. but that's often a bad idea, because it ties your public face - what you're describing to people who will use your code - to your inner details - what you use to do the work behind the scenes. so you can use a class where you would use an interface, hence the confusion.
in fact, you could have a coding standard that says that no public methods should have class names as arguments or as return values. instead they should specify interfaces. that would be a bit obsessive, but is generally good engineering practice.
there's also a historical reason for them in java - in many OO languages you can inherit from many classes at once. this is called multiple inheritance. it can be confusing, so the people who designed java decided not to allow it. that means that when you want to inherit from more than one thing, you end up using interfaces to do the work of classes in a half-baked kind of way, and then type in a lot of extra methods all over the place. that's just krunky java for you. the good explanation is the first one (which is what everyone is saying in different ways, really).
posted by andrew cooke at 9:34 AM on January 14, 2005
inheritance is a way of building/extending code.
unfortunately, the separation isn't clean because you can use a class in a specification instead of an interface. but that's often a bad idea, because it ties your public face - what you're describing to people who will use your code - to your inner details - what you use to do the work behind the scenes. so you can use a class where you would use an interface, hence the confusion.
in fact, you could have a coding standard that says that no public methods should have class names as arguments or as return values. instead they should specify interfaces. that would be a bit obsessive, but is generally good engineering practice.
there's also a historical reason for them in java - in many OO languages you can inherit from many classes at once. this is called multiple inheritance. it can be confusing, so the people who designed java decided not to allow it. that means that when you want to inherit from more than one thing, you end up using interfaces to do the work of classes in a half-baked kind of way, and then type in a lot of extra methods all over the place. that's just krunky java for you. the good explanation is the first one (which is what everyone is saying in different ways, really).
posted by andrew cooke at 9:34 AM on January 14, 2005
you should avoid inheritance whenever possible
not using inheritance is good advice. all your code gets tied up in inheritance trees and often no-one has thought carefully enough about what should be private and public in their classes, so changing a silly detail in one class ends up breaking a class that extends it.
that's critical in understanding this. people (well, me, and programmers i know) start of using inheritance way too much because it's what they teach you when you're learning oo programming. but really it's just this weird way of extending code that isn't as great as you first thought.
interfaces, on the other hand, are how you describe what classes should look like. that's really useful and shouldn't be mixed up with how you sometimes want to reuse code.
posted by andrew cooke at 9:40 AM on January 14, 2005
not using inheritance is good advice. all your code gets tied up in inheritance trees and often no-one has thought carefully enough about what should be private and public in their classes, so changing a silly detail in one class ends up breaking a class that extends it.
that's critical in understanding this. people (well, me, and programmers i know) start of using inheritance way too much because it's what they teach you when you're learning oo programming. but really it's just this weird way of extending code that isn't as great as you first thought.
interfaces, on the other hand, are how you describe what classes should look like. that's really useful and shouldn't be mixed up with how you sometimes want to reuse code.
posted by andrew cooke at 9:40 AM on January 14, 2005
grumblebee: Let's say you wanted to interact with a database, but wanted to support a variety of databases. You could define an interface describing the functions you needed all databases to have, like
DatabaseInterface:
Record GetNewestRecord();
void SaveRecord(Record r);
You could then define:
MysqlDriver implements DatabaseInterface:
Record GetNewestRecord()
{
// do this the mysql way
}
void SaveRecord(Record r);
{
// do this the mysql way
}
And do the same thing for oracle, access and postgresql.
In your main code you would only need to say you want to work with any class that implements DatabaseInterface and not have to worry about the implementation details. The fact that MysqlDriver implements DatabaseInterface guarantees that you can call SaveRecord on any class implementing the interface with the same arguments and have it return the same type. You could even let others create their own database drivers by publishing the interface and functional requirements of each function.
I don't know if this is as deep as a sense you mean, but I hope it helps.
posted by zelphi at 9:41 AM on January 14, 2005
DatabaseInterface:
Record GetNewestRecord();
void SaveRecord(Record r);
You could then define:
MysqlDriver implements DatabaseInterface:
Record GetNewestRecord()
{
// do this the mysql way
}
void SaveRecord(Record r);
{
// do this the mysql way
}
And do the same thing for oracle, access and postgresql.
In your main code you would only need to say you want to work with any class that implements DatabaseInterface and not have to worry about the implementation details. The fact that MysqlDriver implements DatabaseInterface guarantees that you can call SaveRecord on any class implementing the interface with the same arguments and have it return the same type. You could even let others create their own database drivers by publishing the interface and functional requirements of each function.
I don't know if this is as deep as a sense you mean, but I hope it helps.
posted by zelphi at 9:41 AM on January 14, 2005
Interfaces allow us to use things that have a common behavior in a unified fashion.
For example, we can use an electric drill to spin a drill bit, a mixer from a hand mixer, a paint brush, or anything else with a cylindrical shaft.
The physical interface here is the cylinder and the behavior is twisting.
Programming interfaces allow one to do much the same thing. We create interfaces when we want to address different things by the behavior they exhibit--being twistable in my example.
So, going back to the Comparable interface, we have a common behavior--comparing one object to another--that we can use in a unified fashion (comparing all of the elements of a heterogeneous collection).
The usual warning about taking analogies to far applies here.
posted by AmaAyeRrsOonN at 9:51 AM on January 14, 2005
For example, we can use an electric drill to spin a drill bit, a mixer from a hand mixer, a paint brush, or anything else with a cylindrical shaft.
The physical interface here is the cylinder and the behavior is twisting.
Programming interfaces allow one to do much the same thing. We create interfaces when we want to address different things by the behavior they exhibit--being twistable in my example.
So, going back to the Comparable interface, we have a common behavior--comparing one object to another--that we can use in a unified fashion (comparing all of the elements of a heterogeneous collection).
The usual warning about taking analogies to far applies here.
posted by AmaAyeRrsOonN at 9:51 AM on January 14, 2005
Best answer: An interface describes a subset of functionality that you might want several different, otherwise unrelated classes to have. As an example, you might want a bunch of classes to be able to generate XML representations of themselves. So you define an interface ICanMakeXML that specifes a method ToXML() that returns (say) a string of XML.
Every class that implements this interface makes the following promise: You can call my ToXML() method, and I'll give you some XML that represents my state.
So if I have some classes, Apples, Oranges, and KineticEnergyWeapons, which might not have an inheritance relationship (Apples and Oranges are both Fruit, but not KineticEnergyWeapons) but which implement ICanMakeXML, you can get the XML data out of them by calling their ToXML() method.
One very useful thing about this is that you can now define other functions, methods, classes, etc. that work on ICanMakeXML objects, instead of having to care what their actual type is.
The usual use for this is in frameworks for building applications, where you define interfaces like ICanSaveMyself, ICanMakeAWebPageOutOfMyself, IComplyWithYourWeakAssAuthenticationProtocol, and so forth.
posted by jimfl at 10:01 AM on January 14, 2005
Every class that implements this interface makes the following promise: You can call my ToXML() method, and I'll give you some XML that represents my state.
So if I have some classes, Apples, Oranges, and KineticEnergyWeapons, which might not have an inheritance relationship (Apples and Oranges are both Fruit, but not KineticEnergyWeapons) but which implement ICanMakeXML, you can get the XML data out of them by calling their ToXML() method.
One very useful thing about this is that you can now define other functions, methods, classes, etc. that work on ICanMakeXML objects, instead of having to care what their actual type is.
The usual use for this is in frameworks for building applications, where you define interfaces like ICanSaveMyself, ICanMakeAWebPageOutOfMyself, IComplyWithYourWeakAssAuthenticationProtocol, and so forth.
posted by jimfl at 10:01 AM on January 14, 2005
Interfaces are a way of a class specifiying a set of tasks it can do (say, a set of methods for "web server") without having to be inherited from anything particular. So you say it implements WebServer, which is a small class that just defines the set of methods that WebServer-implementing classes should be able to perform. In, say, C++, which has multiple inheritance, you'd set up a WebServer class and have it inherit from both that and whatever other class is its primary one. Java simplifies it a bit with interfaces.
posted by abcde at 10:43 AM on January 14, 2005
posted by abcde at 10:43 AM on January 14, 2005
Response by poster: One very useful thing about this is that you can now define other functions, methods, classes, etc. that work on ICanMakeXML objects, instead of having to care what their actual type is.
This is helpful. Most people are explaining how to set up an interface relationship, but not how to use one. Let's see if I get this:
I create an interface called Weapon. Anything with that implements Weapon can Kill(). I now create the following classes that all implement Weapon: sword, gun, club and mace.
Let's say this is for a game, and we won't know what weapon type the user will decide to use until RUNTIME. They eventually pick a weapon (let's say a club), and we can then say...
someVar = whatEverTheUserPicked;
now, we can say someVar.kill() without having to know which weapon they are killing with. Each weapon can have its own way of killing. We don't care.
Is this right? Also, even if it is right, is this the main way one would use an interface, or am I missing some subtle point. My example seems really easy to me, but I never see it explained this clearly. Which makes me think I'm not getting something. Is the main advantage being able to hold off certain decisions until runtime?
posted by grumblebee at 10:48 AM on January 14, 2005
This is helpful. Most people are explaining how to set up an interface relationship, but not how to use one. Let's see if I get this:
I create an interface called Weapon. Anything with that implements Weapon can Kill(). I now create the following classes that all implement Weapon: sword, gun, club and mace.
Let's say this is for a game, and we won't know what weapon type the user will decide to use until RUNTIME. They eventually pick a weapon (let's say a club), and we can then say...
someVar = whatEverTheUserPicked;
now, we can say someVar.kill() without having to know which weapon they are killing with. Each weapon can have its own way of killing. We don't care.
Is this right? Also, even if it is right, is this the main way one would use an interface, or am I missing some subtle point. My example seems really easy to me, but I never see it explained this clearly. Which makes me think I'm not getting something. Is the main advantage being able to hold off certain decisions until runtime?
posted by grumblebee at 10:48 AM on January 14, 2005
Best answer: [This got to be pretty long as I was writing it. Two sections: an intuitive explanation based on analogy, and then a concrete explanation of how the ideas in that analogy work in a real programming language.]
One of the things that confuses people about interfaces is that they are related to the concept of inheritance but they're not really the same thing.
Say you've got a class SonyStereo that has two methods:
- void play()
- void adjustVolume(int level)
We can call these two method names and the types they take and return SonyStereo's interface -- as far as the outside world is concerned, a SonyStereo object is nothing but a black box with two knobs on it: play and adjustVolume. Now, if you make a new class, SonyFancyStereo, which inherits from SonyStereo, SonyFancyStereo objects are also (to the outside world) just black boxes with the same two knobs on them (and maybe people who are 'in the know' about the special features of SonyFancyStereo objects can also see a new button, shufflePlaySixCDs, that other people can't see).
Since SonyFancyStereo inherits from SonyStereo, if you were take a SonyFancyStereo object and crack open the box you'd see that it's obvious why it has all the same knobs a SonyStereo has: when you look at the wiring, it's just a SonyStereo except that somebody added a six-CD changer, added some new circuits, and replaced them with new ones to make the new functionality. This is normal inheritance.
But now lets say that you want to make a competing object, AlpineStereo. Since people already know how to use SonyStereos, you'd like to make your AlpineStereo work just like it. However, you don't want to use a SonyStereo as your base, (a) because you don't have access to Sony's schematics and (b) because Sony guts are crap anyways and you'd prefer to do your own thing. So you make your AlpineStereo have the same knobs:
- void play()
- void adjustVolume(int level)
and now everybody who knows how to use SonyStereos should also know how to use your new AlpineStereos, even though if you were to crack open the black box you'd see that inside it is nothing like a SonyStereo at all. AlpineStereo is said to implement the same interface as SonyStereo even though it does not inherit from SonyStereo and shares none of SonyStereo's implementation.
After a few more people enter the market making SonyStereo-compatible stereos, somebody might have the bright idea to recognize that the fundamental interface that they all use:
- void play()
- void adjustVolume(int level)
has nothing to do with SonyStereos at all and in fact it ought to be considered a separate document that stands apart from any particular class that implements a stereo. The document doesn't say anything about how to build a stereo -- nobody could agree on that anyway, since everybody has their own ideas of how to do it, which is the whole reason there are multiple vendors anyway -- but it does specify how to use one. So somebody publishes the StereoInterface standard, and pretty soon all the black-box stereos on the market are sporting a sexy "Implements the StereoInterface standard!" sticker. Now everybody's happy: manufacturers can make a new kind of stereo without having to base its guts on the old SonyStereo, and consumers can buy any kind of stereo they want and be sure they'll know how to use it.
Okay, that's the implementor's side of the story. Now let's say you're a customer. If you're like my mom, you'll go to the store and see the AlpineStereo and say to yourself, "Hmm ... this is strange. It looks familiar, but I only know how to use SonyStereos so even though the AlpineStereo looks good I'm going to buy the SonyStereo anyway because I know how to use it." She is programmed to accept new objects by implementation, not interface, so she only buys the SonyStereos even though there are other stereos available (though she might certainly end up taking home the SonyFancyStereo by accident ... my mom can be a little spacey). But if you're like my dad, you go to the store and say, "Goddamn those piece-of-crap SonyStereos! I hate them! But this AlpineStereo ... well, it says it supports the StereoInterface standard, and it can't be as bad as that Sony crap, so let's give it a shot." He's programmed to accept new objects by interface, so he'll use anything that implements StereoInterface, regardless of its implementation.
Okay, that's an analogy that'll help you understand what the idea behind interfaces is. To bring this into an object-oriented programming language, we'll need to turn those concepts into some kind of actual code. Let's take another example: you've written a comparison-based sorting method for Integers in Java, but you'd like to use the same code to sort all kinds of different things, not just Integers. If you wrote your code like
// sort the given array in ascending order
void sort(Integer[] unsorted) { ... }
it's copy-n-paste time; there's no way to make it also sort Strings (though you could sort subclasses of Integer, setting aside the fact that you can't have subclasses of Integer since it's declared to be final).
But really you don't need for the things your sort method takes to be Integers per se; all your code really cares about is being able to tell, given two of the things it's sorting, which one is bigger. As it happens, Java supports an explicit notion of interfaces so that Integer and String can (and do) put on their boxes a sexy sticker that says "Supports the Comparable interface!" meaning that it has a method compareTo(Object other) that will return some value that tells you whether the object you invoked the method on or the object you passed to it was bigger. So if you rewrite your code using that compareTo method everywhere you used to use < and then you change your method signature to read
// sort the given array in ascending order
void sort(Comparable[] unsorted) { ... }
your method will be able to sort Strings or Integers or anything else that supports the Comparable interface equally well. (Even though Strings and Integers don't have anything to do with each other, and it would make no sense to have one of them inherit from the other. They do both inherit from Object, but it also makes no sense for Object to have a compareTo method, since you can't in general compare any old objects to each other.) And you can make new classes that also implement the same interface:
class MyFantasticClass implements Comparable {
... public int compareTo(Object o) { ... } ...
}
They'll work with your sorting method too. (You can mix and match implementing any number of interfaces with inheriting from a base class in Java: class MyFantasticClass extends MyBoringClass implements Comparable, Runnable { ... } is just fine.)
Java also has a mechanism for declaring your own interfaces: you just say
interface MyInterfaceName {
... int methodOne(); ...
... int methodTwo(); ...
}
It's like a class declaration, but there are only method declarations and there aren't any bodies, and everything is implicitly considered public. (It makes no sense to declare a private method in an interface: that would be telling the stereo manufacturers from before how to build their stereos).
People also program interfaces in C++, but it's much nastier since C++ had this notion of interfaces kind of hacked in rather than being designed with them in mind. In C++, your "interfaces" are actually just regular classes with nothing in them but virtual methods that have no bodies (there's a stupid C++ trick for this, where you say virtual int myMethod() = 0; which tells the C++ compiler to make an entry in the vtable for myMethod without actually having any code associated with it; if you try to call that method directly you get a runtime error). To implement one of these interfaces, you just inherit from it, overriding the pure-virtual methods the interface specifies with real methods that have bodies. Since C++ unlike Java allows multiple inheritence, you can use this trick to implement any number of interfaces and also inherit from a normal base class if you want.
Note that these funny declarations in C++ and Java are intended help you out concretely by giving you two things: (1) the compiler will check to make sure that everything you say implements a particular interface actually implements the whole interface, and (2) to give you a type that's just that interface so that code you write elsewhere can refer to it instead of a base class of some particular implementation (otherwise you couldn't actually use the flexibility these interfaces give you: you can't write "void sort(Comparable[] unsorted)" if Comparable isn't a legal type). In un(statically)typed languages like Python or PHP, you don't get or need #2; if you want to send in some random object to method, you're welcome to. There's still some benefit to #1, but it's not really a deal-breaker not to have it: some untyped languages (e.g. many Scheme object systems) have explicit interface declarations, and others (e.g. Python if my memory serves) don't.
Whew! That was a lot longer than I expected. Hopefully that helps you out.
posted by jacobm at 10:50 AM on January 14, 2005
One of the things that confuses people about interfaces is that they are related to the concept of inheritance but they're not really the same thing.
Say you've got a class SonyStereo that has two methods:
- void play()
- void adjustVolume(int level)
We can call these two method names and the types they take and return SonyStereo's interface -- as far as the outside world is concerned, a SonyStereo object is nothing but a black box with two knobs on it: play and adjustVolume. Now, if you make a new class, SonyFancyStereo, which inherits from SonyStereo, SonyFancyStereo objects are also (to the outside world) just black boxes with the same two knobs on them (and maybe people who are 'in the know' about the special features of SonyFancyStereo objects can also see a new button, shufflePlaySixCDs, that other people can't see).
Since SonyFancyStereo inherits from SonyStereo, if you were take a SonyFancyStereo object and crack open the box you'd see that it's obvious why it has all the same knobs a SonyStereo has: when you look at the wiring, it's just a SonyStereo except that somebody added a six-CD changer, added some new circuits, and replaced them with new ones to make the new functionality. This is normal inheritance.
But now lets say that you want to make a competing object, AlpineStereo. Since people already know how to use SonyStereos, you'd like to make your AlpineStereo work just like it. However, you don't want to use a SonyStereo as your base, (a) because you don't have access to Sony's schematics and (b) because Sony guts are crap anyways and you'd prefer to do your own thing. So you make your AlpineStereo have the same knobs:
- void play()
- void adjustVolume(int level)
and now everybody who knows how to use SonyStereos should also know how to use your new AlpineStereos, even though if you were to crack open the black box you'd see that inside it is nothing like a SonyStereo at all. AlpineStereo is said to implement the same interface as SonyStereo even though it does not inherit from SonyStereo and shares none of SonyStereo's implementation.
After a few more people enter the market making SonyStereo-compatible stereos, somebody might have the bright idea to recognize that the fundamental interface that they all use:
- void play()
- void adjustVolume(int level)
has nothing to do with SonyStereos at all and in fact it ought to be considered a separate document that stands apart from any particular class that implements a stereo. The document doesn't say anything about how to build a stereo -- nobody could agree on that anyway, since everybody has their own ideas of how to do it, which is the whole reason there are multiple vendors anyway -- but it does specify how to use one. So somebody publishes the StereoInterface standard, and pretty soon all the black-box stereos on the market are sporting a sexy "Implements the StereoInterface standard!" sticker. Now everybody's happy: manufacturers can make a new kind of stereo without having to base its guts on the old SonyStereo, and consumers can buy any kind of stereo they want and be sure they'll know how to use it.
Okay, that's the implementor's side of the story. Now let's say you're a customer. If you're like my mom, you'll go to the store and see the AlpineStereo and say to yourself, "Hmm ... this is strange. It looks familiar, but I only know how to use SonyStereos so even though the AlpineStereo looks good I'm going to buy the SonyStereo anyway because I know how to use it." She is programmed to accept new objects by implementation, not interface, so she only buys the SonyStereos even though there are other stereos available (though she might certainly end up taking home the SonyFancyStereo by accident ... my mom can be a little spacey). But if you're like my dad, you go to the store and say, "Goddamn those piece-of-crap SonyStereos! I hate them! But this AlpineStereo ... well, it says it supports the StereoInterface standard, and it can't be as bad as that Sony crap, so let's give it a shot." He's programmed to accept new objects by interface, so he'll use anything that implements StereoInterface, regardless of its implementation.
Okay, that's an analogy that'll help you understand what the idea behind interfaces is. To bring this into an object-oriented programming language, we'll need to turn those concepts into some kind of actual code. Let's take another example: you've written a comparison-based sorting method for Integers in Java, but you'd like to use the same code to sort all kinds of different things, not just Integers. If you wrote your code like
// sort the given array in ascending order
void sort(Integer[] unsorted) { ... }
it's copy-n-paste time; there's no way to make it also sort Strings (though you could sort subclasses of Integer, setting aside the fact that you can't have subclasses of Integer since it's declared to be final).
But really you don't need for the things your sort method takes to be Integers per se; all your code really cares about is being able to tell, given two of the things it's sorting, which one is bigger. As it happens, Java supports an explicit notion of interfaces so that Integer and String can (and do) put on their boxes a sexy sticker that says "Supports the Comparable interface!" meaning that it has a method compareTo(Object other) that will return some value that tells you whether the object you invoked the method on or the object you passed to it was bigger. So if you rewrite your code using that compareTo method everywhere you used to use < and then you change your method signature to read
// sort the given array in ascending order
void sort(Comparable[] unsorted) { ... }
your method will be able to sort Strings or Integers or anything else that supports the Comparable interface equally well. (Even though Strings and Integers don't have anything to do with each other, and it would make no sense to have one of them inherit from the other. They do both inherit from Object, but it also makes no sense for Object to have a compareTo method, since you can't in general compare any old objects to each other.) And you can make new classes that also implement the same interface:
class MyFantasticClass implements Comparable {
... public int compareTo(Object o) { ... } ...
}
They'll work with your sorting method too. (You can mix and match implementing any number of interfaces with inheriting from a base class in Java: class MyFantasticClass extends MyBoringClass implements Comparable, Runnable { ... } is just fine.)
Java also has a mechanism for declaring your own interfaces: you just say
interface MyInterfaceName {
... int methodOne(); ...
... int methodTwo(); ...
}
It's like a class declaration, but there are only method declarations and there aren't any bodies, and everything is implicitly considered public. (It makes no sense to declare a private method in an interface: that would be telling the stereo manufacturers from before how to build their stereos).
People also program interfaces in C++, but it's much nastier since C++ had this notion of interfaces kind of hacked in rather than being designed with them in mind. In C++, your "interfaces" are actually just regular classes with nothing in them but virtual methods that have no bodies (there's a stupid C++ trick for this, where you say virtual int myMethod() = 0; which tells the C++ compiler to make an entry in the vtable for myMethod without actually having any code associated with it; if you try to call that method directly you get a runtime error). To implement one of these interfaces, you just inherit from it, overriding the pure-virtual methods the interface specifies with real methods that have bodies. Since C++ unlike Java allows multiple inheritence, you can use this trick to implement any number of interfaces and also inherit from a normal base class if you want.
Note that these funny declarations in C++ and Java are intended help you out concretely by giving you two things: (1) the compiler will check to make sure that everything you say implements a particular interface actually implements the whole interface, and (2) to give you a type that's just that interface so that code you write elsewhere can refer to it instead of a base class of some particular implementation (otherwise you couldn't actually use the flexibility these interfaces give you: you can't write "void sort(Comparable[] unsorted)" if Comparable isn't a legal type). In un(statically)typed languages like Python or PHP, you don't get or need #2; if you want to send in some random object to method, you're welcome to. There's still some benefit to #1, but it's not really a deal-breaker not to have it: some untyped languages (e.g. many Scheme object systems) have explicit interface declarations, and others (e.g. Python if my memory serves) don't.
Whew! That was a lot longer than I expected. Hopefully that helps you out.
posted by jacobm at 10:50 AM on January 14, 2005
What everyone else said and:
1) There are two types of inheritance, interface and implementation. Interface defines the messages the object can receive. Implementation defines the default behavior.
2) Java implements multiple interface inheritance and single implementation inheritance.
3) Just because someone has implemented an interface doesn't mean the code will do what you expect. The contract only specifies the communication between the objects.
4) Interfaces help in creating a loosely coupled design in statically typed languages.
I would recommend Agile Software Development as an introduction to object/software design.
5) Interfaces are required in statically typed languages so that the calling code knows that it can communicate with the object. These are not required in dynamic typed languages as the calling object doesn't care as long as the object responds to the message.
posted by voon_42 at 11:20 AM on January 14, 2005
1) There are two types of inheritance, interface and implementation. Interface defines the messages the object can receive. Implementation defines the default behavior.
2) Java implements multiple interface inheritance and single implementation inheritance.
3) Just because someone has implemented an interface doesn't mean the code will do what you expect. The contract only specifies the communication between the objects.
4) Interfaces help in creating a loosely coupled design in statically typed languages.
I would recommend Agile Software Development as an introduction to object/software design.
5) Interfaces are required in statically typed languages so that the calling code knows that it can communicate with the object. These are not required in dynamic typed languages as the calling object doesn't care as long as the object responds to the message.
posted by voon_42 at 11:20 AM on January 14, 2005
Hey grumblebee, I read your Weapon interface example and I think it demonstrates the understanding of what an interface is for.
And to MetaAskMe: I think jimfl and jacobm's explanations are the clearest. Nice job guys. I'm encouraged to ask programming questions in the future on here :-)
posted by onalark at 11:44 AM on January 14, 2005
And to MetaAskMe: I think jimfl and jacobm's explanations are the clearest. Nice job guys. I'm encouraged to ask programming questions in the future on here :-)
posted by onalark at 11:44 AM on January 14, 2005
Response by poster: Thank you so much, folks. Those were all awesome answers. And a special thanks for jacobm, for writing so clearly at such length. That answer was fantastic.
posted by grumblebee at 12:19 PM on January 14, 2005
posted by grumblebee at 12:19 PM on January 14, 2005
Best answer: grumblebee, your Weapon example is good, but let's take it one step further to illustrate why interfaces are better than multiple inheritance. Still simplistic and contrived, but it should illustrate the issue.
Say you have Weapons and Tools.
With Weapons, you can:
- Kill
- Repair
With Tools, you can:
- FixProblem
- Repair
Maybe an A-bomb can only be a Weapon, but a knife can be a Tool and a Weapon.
If a knfe is a Tool and a Weapon, and you call:
knife.Repair()
Do you Repair it as a Tool or a Weapon? The answer is neither - you Repair is as a knife, because this may be different from how you Repair a gun, and irrelevant to whether it's a Tool or a Weapon. There may be a reference implementation for Repair, but that's likely not going to include any of the the special purpose instructions - like Sharpen - that are needed for repairing a knife. With abstract base classes (where the implementation for the shared method is included in the ABC), you run the risk that Weapon.Repair will be something like "take it to the weapon shop" (figuratively speaking) and Tool.Repair will be "take it to the hardware store", with no way to resolve the conflict. Interfaces let you settle the implementation with the class, where it belongs.
If you want a reference implementation that implements multiple interfaces, you can do that, and subclass from that for particulars.
posted by Caviar at 1:33 PM on January 14, 2005
Say you have Weapons and Tools.
With Weapons, you can:
- Kill
- Repair
With Tools, you can:
- FixProblem
- Repair
Maybe an A-bomb can only be a Weapon, but a knife can be a Tool and a Weapon.
If a knfe is a Tool and a Weapon, and you call:
knife.Repair()
Do you Repair it as a Tool or a Weapon? The answer is neither - you Repair is as a knife, because this may be different from how you Repair a gun, and irrelevant to whether it's a Tool or a Weapon. There may be a reference implementation for Repair, but that's likely not going to include any of the the special purpose instructions - like Sharpen - that are needed for repairing a knife. With abstract base classes (where the implementation for the shared method is included in the ABC), you run the risk that Weapon.Repair will be something like "take it to the weapon shop" (figuratively speaking) and Tool.Repair will be "take it to the hardware store", with no way to resolve the conflict. Interfaces let you settle the implementation with the class, where it belongs.
If you want a reference implementation that implements multiple interfaces, you can do that, and subclass from that for particulars.
posted by Caviar at 1:33 PM on January 14, 2005
i like voon_42's summary, but would say that untyped (or dynamically typed or whatever terminology you want to use - i really don't want to get into that argument) also need and use well-defined interfaces. they just don't have a way of specifying them in the programming language itself (so you end up with comments or unit tests or...)
posted by andrew cooke at 4:45 AM on January 15, 2005
posted by andrew cooke at 4:45 AM on January 15, 2005
Thanks to everyone for a fantastic discussion and furthering my understanding of inheritance.
posted by yerfatma at 9:32 AM on January 16, 2005
posted by yerfatma at 9:32 AM on January 16, 2005
« Older I've lost my Microsoft Office install disk. Is it... | Looking for nice hotels in DC Newer »
This thread is closed to new comments.
posted by seinfeld at 8:13 AM on January 14, 2005