Interfaces allow a great deal of freedom, since they specify behavior vs. specifying an implementation. In some model-based testing that I am working on, Nodes use an interface called Driver to move through their testing:
Driver specifies just two methods: registerState, which stores a State object for testing, and run, which executes the implementing class's behavior. Right now, I have some classes that use Selenium for testing that implement Driver. If I decide in the future to use a different web driver, say Canoo Webtest, all I have to do is create some classes that handle Canoo Webtest, and have them implement Driver. Then, I can plug them into a Node object, and can go on testing without doing a bunch of recoding.
Say you and I both write a classes that do something cool, albiet slightly differently - they would be so cool that every software company out there would want to use one or the other in their application, and pay one uf us LOTS of money.
You write your class, and give everyone the API for your class. They write references to the name of your class, using your methods:
MuraliClass mc = new MuraliClass(int a, int b, string c);
I write my class, and have my class implement an interface. I then give all of MY customers the Interface (the name of the interface and the method signiatures), and they code everything against it"
FredInterface fi = new FredInterface(int a, string b, string c);
now, a year goes by. We both work on improving our classes. We both discover that we can write something BETTER, that is faster, more efficient, and uses less memory. You write a new class, and call it "MuraliClassTwo". I write a new class, and call it FredClassTwo. Your customer has to re-write all their code and change all their references to MuraliClassTwo. My customers DON'T HAVE TO TOUCH THEIR CODE, because they are still getting a FredInterface, even though the underlying class has changed.
There are only two hard things in computer science: cache invalidation, naming things, and off-by-one errors