Seeing an Example Interface in Action
The .NET Framework contains dozens of built-in class interfaces, but these don’t represent the entire universe of interfaces you can use in your programs. Just as you can create your own class definitions, you can also create your own interface definitions. This concept is important, so this section provides a simple example before getting into a more complex, game-related example. You’ll find this program in the folder InterfaceExample in the source code that comes with this book.| Note | You can download the source code from the Downloads section of the Apress Web site ([http://www.apress.com]) if you haven’t done so already. |
The InterfaceExample project is a different project style than you’ve seen thus far in the book. You’ll implement this program as a console application because it doesn’t require any user input. A console application runs in a command prompt (called a DOS prompt back in the day), and all input and output happens via the console, or the command line. You select the project type on the same dialog box where you first name the project, shown in Figure 6-1.

Figure 6-1: Creating a console application
The interface you’ll create and then implement is IIntegerSequencer. Any class that implements the IIntegerSequencer interface is expected to spit out a sequence of integers. The interface itself consists of a single member definition, a method named GetNext:
Interface IIntegerSequencer
Function GetNext() As Integer
End Interface
Remember, an interface by itself is simply a declaration of functionality. It doesn’t provide any implementation of that functionality. To use the interface, you need to declare a class and state that the class implements the desired interface:
Public Class IntegerCounter
Implements IIntegerSequencer
Something pretty cool happens in Visual Studio .NET as soon as you declare a class and then complete the Implements line as shown. Visual Studio “stubs out” all of the members of that interface for you, as shown in Listing 6-1.Listing 6.1: Stubbing Out Interface Members
Public Class IntegerCounter
Implements IIntegerSequencer
Public Function GetNext() As Integer _
Implements IIntegerSequencer.GetNext
End Function
End Class
Creating the IntegerCounter Class
Visual Studio created the function template for the GetNext method on the IntegerCounter class as soon as you hit Enter on the line that reads Implements IIntegerSequencer. If IIntegerSequencer had more members besides the lone GetNext method, these members would also have been stubbed out in the new class declaration.
All that remains is to write the code that implements the GetNext interface for this class. The intention of the IntegerCounter class is to simply count upward each time the GetNext method is called, so this class is pretty trivial to implement (see Listing 6-2).Listing 6.2: A Counter Class That Implements the IIntegerSequencer Interface
Public Class IntegerCounter
Implements IIntegerSequencer
Private FLast As Integer = 1
Public Function GetNext() As Integer _
Implements IIntegerSequencer.GetNext
FLast += 1
Return FLast
End Function
End Class
All this class has to do is keep track of the last integer returned via a private variable named FLast. When the GetNext method is called, the program adds 1 to the variable and returns it. Instant counting class!
Creating the FibonacciCounter Class
Proving you can move beyond the trivial to the merely simple, the second implementation of the IIntegerSequencer class returns the Fibonacci sequence. For the math-impaired, the Fibonacci sequence starts with the integers 1, 1 and then obtains each subsequent number by adding the two numbers before it. The beginning of the sequence is as follows: 1, 1, 2, 3, 5, 8, 13, 21, 34.... Listing 6-3 shows the FibonacciCounter class, which returns the next value in the Fibonacci sequence each time the GetNext method is called.Listing 6.3: The FibonacciCounter Class
Public Class FibonacciCounter
Implements IIntegerSequencer
Dim iTurn As Integer = 0
Private FLast1 As Integer = 1
Private FLast2 As Integer = 1
Public Function GetNext() As Integer _
Implements IIntegerSequencer.GetNext
Dim iTemp As Integer
iTurn += 1
If iTurn < 3 Then
Return 1
Else
iTemp = FLast1 + FLast2
FLast1 = FLast2
FLast2 = iTemp
Return iTemp
End If
End Function
End Class
This class returns a 1 for the first two turns (as the rules of the Fibonacci sequence state). After the second turn, the program returns the sum of the variables FLast1 and FLast2 and then “slides” the values over—placing the value of FLast2 into FLast1 and placing the new sum into FLast2.
Achieving Polymorphism Using the Sequencer Classes
You’ve now got two classes that implement the IIntegerSequencer interface, and neither of these classes inherits from the other. Can a program access either one of the classes polymorphically without knowing which one it’s calling? This would be a short chapter if the answer was “no,” wouldn’t it? Listing 6-4 demonstrates how the program selects one of the two classes randomly and then displays the beginning of that class’s sequence.Listing 6.4: Accessing a Class Interface Polymorphically
Sub Main()
Dim oInt As IIntegerSequencer
Dim oRand As New Random
Dim i As Integer
If oRand.Next(0, 1000) Mod 2 = 0 Then
oInt = New IntegerCounter
Else
oInt = New FibonacciCounter
End If
Console.WriteLine("couting started ")
Do
i = oInt.GetNext
Console.Write(i & ",")
Loop Until i > 100
Console.ReadLine()
End Sub
The most important line of this listing, and perhaps of the chapter, is the first line after the Sub Main declaration. A variable named oInt is declared, but it’s not declared to be an instance of a certain class. Instead, it’s declared to be an instance of a certain interface. You might read this declaration in English as “The variable oInt will hold an instance of some class that implements the IIntegerSequencer interface.” And, this, my friends, is how you achieve polymorphism using interfaces. With this capability, the sample program can now point to either an IntegerCounter instance or a FibonacciCounter instance with the variable oInt because each of these classes implements the IIntegerSequencer interface. Furthermore, the program can call the GetNext method on the variable oInt polymorphically because you’ve declared that variable as implementing the IIntegerSequencer interface.
Why Use Interfaces and Not Class Inheritance?
You might be having some trouble distinguishing between writing two classes that implement the same interface and creating classes that inherit from the same ancestor. Admittedly, the difference is subtle, and you can solve a given problem either way. For example, you could’ve easily created a base class named IntegerSequencer and then created two descendant classes from the base class. The previous sample program would change very little and would still provide polymorphic behavior.You should think about inheritance when you want to extend functionality in some way. For example, you may have some type of problem space that you can solve within a class and then some new variation of that problem space, or an extension of it, makes a descendant class seem like the natural way to go. Interfaces, on the other hand, often solve problems where two classes need to provide similar functionality, but the implementation of that functionality may share little or nothing in common. Even the small integer sequencer gives a good example of this. The problem called for creating classes that generate an infinite sequence of integers, but the two classes you ended up creating didn’t use any common code to do this. That is, there’s no baseline functionality that youcould’ve extracted out of each class and placed into an ancestor class. Because no baseline implementation details could be shared, the best solution is to remove all thought of implementation details at the higher level and describe the classes only by a common, newly defined interface, which of course is what you did.