JAL Computing

C++COMProgramming .NET Mac Palm CPP/CLI Hobbies

 

Home
Up

Chapter 9 "Interfaces"

Although I danced around this subject in the tutorial, I never explicitly tried to explain an interface. C# has a key word interface which allows you to describe a contract without any implementation. An interface can contain zero or more abstract methods. You cannot create an instance of an interface.

As I suggested in the tutorial, an interface is similar to a pure virtual class in C++. It describes a set of method signatures, but does not provide any implementation details. An interface describes a contract that is useful to many different classes and is analogous to a mix-in class in C++. An interface is useful when you want to define a type without any implementation details. An interface may be shared by different classes, but each class is free to implement the interface in a different manner.

A Twisted Analogy

If a class is a blueprint from which you can create zero or more objects in memory, then you may ask what is an interface? Well, I have struggled here for a good analogy. You can think of an interface as one of many possible abstract contracts between the builder of a custom building and the client. If you are building tract homes, then you can simply use the stock blueprint, modifying the usual properties such as color. If you are going to build a custom rendition of a home using a blueprint, then the builder and client will need come to verbal contracts about the building. These preliminary verbal contracts do not describe the actual physical details of how the building will be constructed or embellished, but simply codifies an understanding between the principals, the designer/builder and the client. The verbal contract describes what the client wants, but not the gory details on how the goal will be implemented. One verbal agreement might be that building will be be wired for cable TV. Another agreement might be that there will be a home theater addition to the house. The designer/builder and client must then agree on an implementation of the abstract contracts before proceeding with construction. Your construction project inherits from the blueprint and the designer/builder implements zero or more custom design decisions. Thus, in the land of C#, a construction project (concrete class) can inherit from a single blueprint and implement zero or more contracts. More importantly, every building in the land of C# is constructed with absolute precision! Cool!

A Twisted Proposal

Well I am going to go out on a limb here and state that an interface represents an ABSTRACT_IS_A relationship.  As I discussed in Chapter 2, inheritance represents an IS_A relationship from a generalization to a specialization whereas containment represents a HAS_A relationship between a whole and a part. Here again are the two classic relationships expressed in code:

	class Radio 
	{
		...
	}
	class Vehicle
	{
		...
	}
	class Car : Vehicle // inheritance
	{
		Radio r= new Radio();  // containment
	}	

Since an interface is equivalent to a pure virtual class in C++, I argue that an interface is a specialized type of an IS_A relationship, one with no implementation details. For example, if you are coding a generic sort algorithm, Sortable classes can either inherit from a Sortable base class with an abstract Compare method or they can implement an IComparable interface. So an instance of a class that implements IComparable IS_A comparable object. In general terms, an interface represents an IS_A relationship.

Unlike a Sortable base class, the IComparable interface cannot include any implementation details since all methods must be "abstract". So an interface represents a restricted sub type of an IS_A relationship. An instance of a class that implements the IComparable interface does not share any interface implementation details through "inheritance", only the abstraction IComparable is shared. Each class that implements the IComparable interface is free to provide an independent implementation of the abstraction.

So my twisted proposal is that an interface represent a subset of the domain of IS_A relationships, specifically an interface is a purely ABSTRACT_IS_A relationship. Alternatively, you could say that the concrete class IMPLEMENTS_A abstraction.

Note:  Others have argued that an interface represents a LIKE_A relationship where classes share an abstraction and "look like" a given abstraction. Alternatively, some look at interfaces as a CAN_BE relationship where multiple classes "can be" some thing, where "some thing" is an interface. These terms can be useful in identifying a contract that can be useful to many classes through the use of multiple inheritance of interfaces. In summary:

IS_A --> inheritance

HAS_A --> containment

LIKE_A --> multiple inheritance

Sample Code: Pure Abstract Class vs. Interface

The general syntax for a pure abstract class and interface is:

abstract class MyAbstractClass 
{
    public abstract someType MyMethod(...);
    ...
}
interface IMyInterface
{
     someType MyMethod(...);
    ...   
}

Not surprisingly, the syntax for inheriting from a class or implementing an interface is the same:

class MyClass : MyAbstractClass, IMyInterface ...
{
    ...
}

Here again is our pure abstract Drawable class from Chapter 4:

abstract class Drawable
{
    public abstract String DrawYourself();
}
class Circle : Drawable
{
    public override String DrawYourself()
    {
        return "Circle";
    }
}
class Square : Drawable
{
    public override String DrawYourself()
    {
        return "Square";
    }
}

Since the base class Drawable does not contain any implementation details, it can be rewritten as an interface. Here is a slightly different version of the Drawable type implemented as an interface from Chapter 7:

// an interface version of Drawable
interface IDrawable 
{
	void DrawYourself();
}
class Circle : IDrawable 
{
	public void DrawYourself() 
	{
		System.Console.WriteLine("Circle");
	}
}
class Square : IDrawable 
{
	public void DrawYourself() 
	{
		System.Console.WriteLine("Square");
	}
}
 

Here is a graphical view of the Circle Class using the lollipop interface notation.

What's this?

Here is a graphical view of the Square Class using the expanded interface notation.

If you try to create an instance of the IDrawable interface, the compiler will complain:

Cannot create an instance of the abstract class or interface 'TestInterface.IDrawable' 

Using Interfaces vs. Inheritance

If you are designing a contract without any implementation details and the contract is going to be useful to many other classes (eg. a mix in class), then you should use an interface. On the other hand, use a base class if you want to include some implementation details. Be careful though. Once you have published an interface, it is difficult to update an interface. Updating an interface will break all classes that implement the interface, so you need to get it right the first time. If you have an evolving contract, consider using a base class and inheritance. If you must add new methods to the base class, you can provide a default implementation of the new methods. Any classes that inherit from the base class will also inherit the default implementations. Updating the base class in this way does not break any class that inherits from the modified base class. In summary, if you have a well defined contract that will be implemented by many classes use an interface. If the contract is evolving, consider using a base class. Use a base class if you need to include implementation details. 

Remember, your class can only inherit from one class hierarchy, but can implement multiple interfaces. If you accept that interfaces in C# are analogous to pure virtual classes in C++ then, in essence, C# supports single inheritance of implementation and multiple inheritance of interface.

Usage

Sometimes concrete examples are useful to illustrate a new concept. If you are having trouble getting your head around when or how to use an interface, feel free to skip ahead and take a quick look at the interface code in Chapters 13, 15 and 16.

bulletIn Chapter 13, I demonstrate the use of an interface IDrawable to implement a "plug in" architecture. As long as the plug in class implements the interface, you can dynamically load the plug in class and then call the plug in method at runtime. You program to a contract and the plug in agrees to implement the contract.
bullet In Chapter 15 I demonstrate how to sort an ArrayList of non-null strings using a case insensitive IComparer and then demonstrate an algorithm that finds the set of rows in the sorted list that are a partial match to a search key.
bullet In Chapter 16, I discuss the concepts of interface design, composite interfaces and demonstrate the use of an abstract skeletal class.
bulletNote the .NET API's use of marker interfaces: IReadOnlySessionState, INamingContainer and IRequiresSessionState.
bulletFinally, here is a screen shot of a working program from Chapter 19 that uses polymorphism to draw objects on mouse up calling IDrawableShape.DrawYourself(g).

Note: If you are a C/C++ programmer, you may have encountered the concept of a "callback" function. In this idiom, you pass a pointer to a function to a generic method. The declaration of the pointer looks like a function prototype. You can use this idiom to extend a quicksort algorithm in C/C++. You pass a function pointer to the quicksort method and then implement the compare function in the callback method. This allows you to reuse the generic quicksort method. In C#, you can use an interface instead of a pointer to a function to extend a generic sort algorithm. More specifically, your_sortable class implements the IComparable interface. You can then pass an array of your_sortable objects to Array.Sort, reusing the generic Array.Sort algorithm. Finally, C# supports the concept of a Delegate which can be viewed as a type safe function pointer to "some method".

Simulating Multiple Inheritance

Most problems can be solved without multiple inheritance of implementation. Many major frameworks that use multiple inheritance, actually use multiple inheritance of pure virtual classes (aka interfaces). If you really feel the need for multiple inheritance of implementation, consider using containment and delegation to simulate multiple inheritance. In this idiom, you release a skeletal implementation and a matching  interface. The user of your skeleton class and interface creates a concrete implementation of the skeleton class. The user then wraps the concrete object derived from the skeletal class, implements the interface and forwards (delegates) all interface calls to the contained object.

Note: In .NET 2.0, you can do this using generics!

Interface --> AbstractClass --> Class

With practice, the Twisted Coder learns to declare the contract using an Interface, provide default implementations using an AbstractClass and then provide a usable concrete class that extends from the AbstractClass. So if you want to encapsulate the concept of a Version in a class, define the IVersionable interface, provide an abstract class with default implementations of IVersionable called AbstractVersion and finally write a concrete class that extends from AbstractVersion called Version. This allows the user of your class to extend from AbstractVersion, use your concrete Version class or provide their own implementations of IVersionable by implementing IVersionable in their own class.

All Rights Reserved Jeff Louie

<% ShowFooter() %>

 

Send mail to [email protected] with questions or comments about this web site. Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 © 
Last modified: 08/04/09
Hosted by www.Geocities.ws

1