So you've completed your Windows 2000 compatible product and you are ready to release it to the world. One small problem, you've coded for some new Windows API's that aren't available in NT 4.0, and Win2K is still in beta three. Hopefully you've got enough cash on hand to bide your time. This is just one scenario in which using interface-oriented programming can help insulate you and your code from changes beyond your control.
An interface is defined as the set of methods a class can perform plus the set of properties the class exposes. In some languages, there is no difference between a method and a property because each property is represented by pairs of methods such as GetMyProperty() and SetMyProperty(). By forcing others to refer to our classes only via the public interface and by only referencing others via their public interface, we can reduce the shock that typically accompanies future product changes.
Some of you are probably nodding along and thinking to yourselves, "Eric, you've just described Microsoft's COM architecture." You would be right. COM is an interface-oriented architecture, but it does not have a monopoly on this methodology. COM does, however, highlight another important interface-oriented programming technique --naming interfaces. Concerning naming, we should agree to do three things: name the interfaces we support, change the name of the interface if it ever changes and support both the newly named interface as well as the older interface. By following these conventions, the resulting objects will be less brittle when used by newer and older systems. Naming interfaces helps ActiveX components behave well in dozens of versions of different development tools. Incidentally, Microsoft happens to use a large binary number -- called a UID -- to name its interfaces, but that is not required to do interface-oriented programming.
Even if you’re not ready to embrace COM, either because of its complexity or because of your own cross-platform needs, you can still use interfaces to improve your code. Interfaces are natively supported by Java, Visual Basic, Delphi and, indirectly, in C++ -- although various vendors have added direct interface support. In traditional object-oriented solutions, a lot of emphasis is placed on creating a class hierarchy: Classes typically inherit the behaviors of its parents and then add some additional behavior of their own.
Interface-orientation de-emphasizes class hierarchy, replacing it with interface aggregation. Each class then chooses a distinct set of interfaces to implement, without any regard for related classes.
Experience has taught me traditional object-oriented inheritance is often an area that causes good code to turn brittle, especially if an expert didn’t create your original class hierarchy.
Using interfaces in C++, for example, can help you avoid some of the dangers of a bad hierarchy. In C++, an interface definition is typically a pure abstract class -- no implementation -- with only public methods and no member variables. You can then aggregate the interfaces your class supports by using multiple inheritance. You don't have to worry about the horror stories related to using multiple inheritance either. You aren't inheriting any data or implementation, just interfaces. The beauty of this technique is that you can share your classes by sharing header files containing only interfaces, so you have no worries about others making assumptions about how your class works. Since no one can guess how your class works from the header file, you are always free to change the implementation, including adding new interfaces, providing the original interface remains the same.
In addition to providing future flexibility, interface-orientation often simplifies design. Interfaces allow a divide-and-conquer approach to class design by removing or deferring the use of inheritance until implementation. Each logical group of functions that a class should perform can be grouped into an interface definition. Once the desired interfaces are written, similar interfaces can be combined. Traditional inheritance can then be introduced for implementation, if appropriate. In languages that support template programming, you can write templates that will automatically implement the interface for any class that aggregates the template, avoiding implementation inheritance entirely. This is exactly the approach taken by Microsoft’s Active Template Library (ATL).
In the past, PC solutions have often had short lifecycles. But as more enterprise solutions migrate to PCs, we need to adopt techniques that help our solutions last through multiple operating system releases and changes to third party libraries. Interface-oriented programming is one such technique. Your best source for learning interface-oriented programming today is to study how various Windows development tools implement COM. Microsoft’s ATL is complex, but it is a tour de force in interface programming. Armed with these techniques, you can be sure that you are well-insulated before you expose yourself. --Eric Binary Anderson is a development manager at PeopleSoft's PeopleTools division (Pleasanton, Calif.) and has his own consulting business, Binary Solutions. Contact him at firstname.lastname@example.org.