I just picked up on Mike Dinowitz's post Interfaces - Why Bother? asking for benefits that interfaces offer. I started typing a comment, but realised that my two-penn'orth was way too sprawling for a comment and needed a whole post of its own. So here goes - I'm sure this won't be telling someone as experienced as Mike anything he doesn't know, but there's also been a call for more introductory-level blog posts in the last couple of days, so hopefully someone out there will find this useful as a concrete example of where I'd be lost without interfaces.
I'm currently working on a large J2EE platform with over 2000 classes. The only sensible way to manage such complexity is to split it into several distinct modules, each of which is conceptually self-contained and compiled and unit-tested separately, in a strict order. The ANT build script builds the core framework module first, then the email server, then the groups and user modules, etc etc, finally finishing up with the Tapestry-based web interface.
This all works great, except that you're still left with cross-module dependencies. The email server needs to know that group emails should be forwarded to group members, the groups module needs to know about its users, and so on.
The way these dependencies are resolved, is through interfaces. In the email module, we create an interface that represents the bit of group- or member- related functionality that the email server needs to know about - in this case, the ability to accept and propagate an email - and make the group and member objects (which come after the email server) implement that interface.
So we make an interface called EmailPropagator with one method - propagate() - in the email server module, and make groups and members implement EmailPropagator.
This way, the email server doesn't need to know anything else about the "thing" it's sending email to - so long as it implements EmailPropagator, the email server can ask it to propagate email to whoever or wherever it feels like, and that's all that the email server needs to know about it in order to do its job.
We can make anything be accepted by the email server, so long as it implements that one method. It could be a group / mailing list, an individual person, a spam demon that forwards ten thousand copies to random addresses, a black hole that just swallows it up, a file store.... anything, so long as it implements that one method.
This is part of the power of OO, and particularly the power of interfaces. It's also different from inheritance - in Java, and hence CF too, a class can only extend one base class. However, it can implement as many different interfaces as you like. You've heard of "If it looks like a duck and quacks like a duck, it must be a duck...." - well, this extends to "If it quacks like a duck, I don't care what it is, so long as I can ask it to quack".
It's one of the guiding mantras of OO that you should "design to interfaces, not implementations" and this is exactly why - we can make a million different things plug into our email server and do a million different actions with an email, without ever needing to change the email server code. That's power, and that's reusability. And that's why I love interfaces.