In this chapter, you have seen how to use the basic features of inheritance to define an interface based on the interaction between the base class and its derived classes. The Building class example shows how you can use a virtual base Building class and polymorphic inheritance to provide a CallSnowRemoval() method for each derived class. However, there is an alternative way to define an interface.
Recall that the term interface refers to the way a class provides access to the properties and methods of that class. You have seen that this statement:
Public MustOverride Function CallSnowRemoval() As String
in the base class forces each derived class to implement a CallSnowRemoval() method. This means that each derived class has to have a method definition that starts with this statement:
Public Overrides Function CallSnowRemoval() As String
followed by the code that implements the method call. This works fine given the way the classes have been implemented so far. However, suppose a real estate investor decides to purchase some vacation properties. She limits her investments in vacation properties to Florida real estate. She asks you to modify the program to accommodate these new properties. You decide to add a new derived Building class named Vacation . As you design the code for the new derived class, you see that you must implement a CallSnowRemoval() method. But snow removal probably isn't really needed in Florida.
This scenario illustrates a situation you are likely to face in designing classes. In this case, you have several derived classes that have similar needs but one oddball that doesn't fit the mold. Obviously, you could still implement the Vacation class as a derived Building class and add a CallSnowRemoval() method. You'd simply never call the method. That approach would work just fine. However, as you began to write the CallSnowRemoval() code for the Vacation class, you would probably feel like you were adding a wart to an otherwise unblemished piece of code. You would feel as though there must be a better way to solve this problem. There is.
The solution, as described in the following section, is to write an interface declaration.
With interface declarations, any class that wants to use the services of the interface can implement the interface as part of its class definition. Let's stick with the real estate code for this example. You should begin your program modification with the following code:
Interface ISnowRemoval Function CallSnowRemoval() As String End Interface
An interface declaration begins with the keyword Interface , followed by the name of the interface being declared. The default access specifier for an interface declaration is Public . Therefore, you could also write the first line of the interface declaration like this:
Public Interface ISnowRemoval
although most programmers omit the Public keyword. In this example, you are calling the interface ISnowRemoval .
Everything between the Interface and End Interface keywords form the interface statement block. The interface statement block lists all the methods and properties that will become part of the interface.
Note that the interface does not contain code to implement the methods or properties. The interface declaration contains just a list of the method and property names that comprise the interface. If any of the methods use arguments, they must be stated as part of the interface declaration. Collectively, the access specifier (for example, Public ), the method name ( CallSnowRemoval() ), the list of arguments (none in the case of CallSnowRemoval() ), and the return data type (for example, String ) form the signature of the method or property. Therefore, the interface declaration is little more than a list of signatures for the properties and methods in the interface.
If two methods in this example have the same name, but they have different arguments supplied to them, they have different signatures, and Visual Basic .NET can distinguish between them. (You saw this method overloading when you wrote the two different New constructors for the Building class earlier in this chapter.) In an interface, you must provide a complete signature for each method or property that is part of the interface. Again, the interface statement block contains only statements that declare the signatures of the methods and properties that make up the interface.
Implementing the Interface
Any class that wants to use an interface must implement it. This is accomplished via a two-step process. First, the class that wants to use the interface must place this statement in its class code:
Usually, the statement is placed near the top of the code that defines the class. When you place the Implements statement in the class code, you are promising Visual Basic .NET that you will implement each and every method and property that is contained in the Interface declaration. You might hear that by using the Implements keyword in your class code, you are forming a contract to write all the code necessary to implement each signature declared in the interface. If you don't uphold your end of the contract, Visual Basic .NET lets you know about it.
The second step in interface implementation requires you to supply the code that is necessary to implement each of the methods and properties contained in the interface statement block. In the example in this chapter, that requires a statement similar to this:
Public Function CallSnowRemoval() As String Implements _ ISnowRemoval.CallSnowRemoval
Notice that the Implements keyword follows the return data type ( String ) in the statement. This tells Visual Basic .NET that the code that follows is implementing the ISnowRemoval.CallSnowRemoval method of the interface.
The complete code for the Apartment class is shown in Listing 18.5.
Listing 18.5 Complete Code for the Apartment Class After the ISnowRemoval Interface Is Implemented
' ++++++++++++++++++++++++++++ Apartment Class ++++++++++++++++++++++++ Public Class Apartment Inherits Building Implements ISnowRemoval ' We are making a contract with Visual Basic .NET here... Private mUnits As Integer ' The number of apartments Private mRent As Double ' Rent per unit Private mOccupRate As Double ' Occupancy rate for building Public Sub New() End Sub ' Constructor with initializer list of arguments Public Sub New(ByVal Addr As String, ByVal Price As Double, _ ByVal Payment As Double, ByVal Taxes as Double, ByVal Bldg As Integer, ByVal SnowPhone As String) MyBase.Address = Addr MyBase.PurchasePrice = Price MyBase.MonthlyPayment = Payment MyBase.Taxes = Taxes MyBase.BuildingType = Bldg If SnowPhone = "" Then MyBase.SnowRemoval = APTPHONE Else MyBase.SnowRemoval = SnowPhone End If End Sub ' ==================== Properties ====================== Public Property Units() ' Units Get Return mUnits End Get Set(ByVal Value) mUnits = Value End Set End Property Public Property Rents() ' Rents Get Return mRent End Get Set(ByVal Value) mRent = Value End Set End Property Public Property OccupancyRate() As Double ' Occupancy rate Get Return mOccupRate End Get Set(ByVal Value As Double) mOccupRate = Value End Set End Property ' ============== Methods ================== ' We fulfill our contract with Visual Basic .NET here... Public Function CallSnowRemoval() As String Implements _ ISnowRemoval.CallSnowRemoval ' Purpose: This routine is called to remove snow for an Apartment. ' Return "Apartment snow removal: " & MyBase.SnowRemoval End Function Public Sub DisplayBuilding() DisplayBaseInfo() Console.WriteLine(" Apartment members:") Console.WriteLine("Number of Units: " & mUnits) Console.WriteLine("Rent per Unit: " & FormatMoney(mRent)) Console.WriteLine("Occupancy Rate: " & mOccupRate) End Sub End Class
The fourth line in Listing 18.5 uses the Implements keyword to form the contract with Visual Basic .NET to implement the ISnowRemoval interface. The first method defined in the class is the CallSnowRemoval() method, thus fulfilling the contract between the Apartment class and the ISnowRemoval interface. Notice how the code for the CallSnowRemoval() method matches the signature declared in the interface statement block.
Once again, I am carefully distinguishing the terms define and declare. The interface statement block is a declaration that tells Visual Basic .NET what is required of any class that wants to use the interface. On the other hand, the actual code that defines how a class wants to implement the methods or properties is placed within the class itself.
The fact that the class is responsible for writing the actual code points to another advantage of using an interface: Each class that uses the interface can implement it any way it sees fit, as long as it conforms to the signature contained in the interface declaration. Different classes requiring different code to implement the specifics of a method or property is not a problem. This makes using interfaces very flexible, yet interfaces provide a consistent means of using a method or property.
So how does an interface benefit the Vacation class? You've probably already figured out the answer. Because the Vacation class doesn't need to implement a snow removal method, you simply don't add an Implements statement to the Vacation class. By omitting the Implements statement, you are canceling the contract to implement code for the ISnowRemoval interface for the Vacation class.
To implement the interface for the real estate investment program, all you need do is remove the MustOverride statement from the Building class and add the Implements statement and corresponding code to the classes that want to use the ISnowRemoval interface.
To test the new interface, you should substitute the btnProperties object's Click() event code in Listing 18.6 for the code shown in Listing 18.4.
Listing 18.6 Code to Test the ISnowRemoval Interface
Private Sub btnProperties_Click(ByVal sender As Object, ByVal e As _ System.EventArgs) Handles btnProperties.Click Dim CurrentBuilding As Building Dim MyApartment As New Apartment("6 North Ben Street", 550000, 6000, _ 12000, APARTMENT, "555-1000") Dim MyBuilding As New Commercial("250 Industrial Drive", 320000, 3800, _ 5800, COMMERCIAL, "") Dim MyHome As New Home("2 Ghent Court", 140000, 1300, 3300, HOME, "") Dim delta As New Home() Console.WriteLine(MyApartment.CallSnowRemoval()) ' Call it Console.WriteLine(MyBuilding.CallSnowRemoval()) Console.WriteLine(MyHome.CallSnowRemoval()) Console.WriteLine(delta.CallSnowRemoval()) End Sub
If you try to call the CallSnowRemoval() method from a class that does not implement the interface, such as the Vacation class, Visual Basic .NET issues an error message, telling you that CallSnowRemoval() is not a member of the class.