Interface-Based Programming
(Page 1 of 4 )
When you separate the interface from the implementation in your programming, your client is compatible with far more services. This article, the first in a series, introduces you to this key concept of component-oriented programming. It is excerpted from chapter three of
Programming .NET Components, Second Edition, written by Juval Lowy (O'Reilly, 2006; ISBN: 0596007620). Copyright © 2006 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.
As explained in Chapter 1, separation of interface from implementation is a core principle of component-oriented programming. When you separate interface from implementation, the client is coded against an abstraction of a service (the interface), not a particular implementation of it (the object). As a result, changing an implementation detail on the server side (or even switching to a different service provider altogether) doesn’t affect the client. This chapter starts by presenting .NET interfaces and describing what options are available to .NET developers when it comes to enforcing the separation of interface from implementation. It then addresses a set of practical issues involving the definition and use of interfaces, such as how to implement multiple interfaces and how to combine interfaces and class hierarchies. After a detailed look at generic interfaces, the chapter ends with a discussion of interface design and factoring guidelines.
Separating Interface from Implementation
In both C# and Visual Basic 2005, the reserved word interface defines a CLR reference type that can’t have any implementation, can’t be instantiated, and has only public members. Saying that an interface can’t have implementation means that it’s as if all the interface’s methods and properties were abstract. Saying it can’t be instantiated means the same as if the interface were an abstract class (orMustInheritin Visual Basic 2005). For example, this interface definition:
public interface IMyInterface
{
void Method1();
void Method2();
void Method3();
}
is almost equivalent to this class definition:
public abstract class MyInterface
{
public abstract void Method1();
public abstract void Method2();
public abstract void Method3();
}
In traditional object-oriented programming, you typically use an abstract class to define a service abstraction. The abstract class serves to define a set of signatures that multiple classes will implement after deriving from the abstract class. When different service providers share a common base class, they all become polymorphic with that service abstraction, and the client can potentially switch between providers with minimum changes. There are a few important differences between an abstract class and an interface:
An abstract class can still have implementation: it can have member variables or non-abstract methods or properties. An interface can’t have implementation or member variables.
A .NET class can derive from only one base class, even if that base class is abstract. However, a .NET class can implement as many interfaces as required.
- An abstract class can derive from any other class or from one or more interfaces. An interface can derive only from other interfaces.
- An abstract class can have nonpublic (protected or private) methods and properties, even if they are all abstract. In an interface, by definition, all members are public.
- An abstract class can have static methods and static members and can define constants. An interface can have none of those.
- An abstract class can have constructors. An interface can’t.
These differences are deliberately in place, not to restrict interfaces, but rather to provide for a formal public contract between a service provider (the classes implementing the interface) and the service consumer (the client of the classes). Disallowing any kind of implementation details in interfaces (such as method implementations, constants, static members, and constructors) enables .NET to promote loose coupling between the service providers and the client. Because there is nothing in the contract that even hints at implementation, by definition the implementation is well encapsulated behind the interface, and service providers are free to change their implementations without affecting the client. You can even say that the interface acts like a binary shield, isolating each party from the other.
Because interfaces can’t be instantiated, .NET forces clients to choose a particular implementation to instantiate. Having only public members in an interface complements the contract semantics nicely: you would not want a contract with hidden clauses or “fine print.” Everything the contract implies should be public and well defined. The more explicit and well defined a contract is, the less likely it is that there will be conflicts down the road regarding exactly what the class providing the service is required to do. The class implementing the interface must implement all the interface members without exception, because it has committed to providing this exact service definition. An interface can extend only other interfaces, not classes. By deriving a new interface from an existing interface, you define a new and specialized contract, and any class that implements that interface must implement all members of the base interface(s). A class can choose to implement multiple interfaces, just as a person can choose to commit to multiple contracts.
Next: Interface Implementation >>
More .NET Articles
More By O'Reilly Media
|
This article is excerpted from chapter three of Programming .NET Components, Second Edition, written by Juval Lowy (O'Reilly, 2006; ISBN: 0596007620). Check it out today at your favorite bookstore. Buy this book now.
|
|