Lesson 14 - Interfaces in VB.NET
In the previous exercise, Solved tasks for OOP in VB .NET lessons 12-13, we've practiced our knowledge from previous lessons.
In the previous lesson, Solved tasks for OOP in VB .NET lessons 12-13, we practiced working with List collections and created an electronic diary in Visual Basic .NET. In today's tutorial, we'll be getting back into some more theoretical matters. We're going to unveil yet another utility of the object-oriented programming world!
Interface
When one refers to an object's interface, they are referring to how an object is visible from the outside. We already know that an object contains methods that can be set as private or public. The object's interface consists of its public methods, which is the way we communicate with certain types of objects. We have already dealt with public methods in previous lessons, e.g. the ones we set up for our arena warrior. The Warrior class we made had the following public methods:
- Sub Attack(enemy As Warrior)
- Sub Defend(hit As Integer)
- Function Alive() As Boolean
- Sub SetMessage(message As String)
- Function GetLastMessage() As String
- Function HealthBar() As String
If we store a Warrior class instance into a variable, we are able to call the Attack() or Defend() methods on it. Nothing new, right?
As a matter of fact, we are able to declare an interface separately, sort of like we do with classes, and we would then be able to use it as a data type.
We'll give it a go, but on a simpler class than the Warrior class we made. We'll start by creating a new project, a console application, naming it InterfaceSample, and adding a simple class. In my opinion, theoretical concepts should be explained using light examples, meaning not as serious. With that all being said, let's make a bird class! Our bird will be able to chirp, breathe and peck. Our Bird class will look something like this:
Public Class Bird Public Sub Chirp() Console.WriteLine("♫ ♫ ♫") End Sub Public Sub Breathe() Console.WriteLine("Breathing...") End Sub Public Sub Peck() Console.WriteLine("Peck, peck!") End Sub End Class
Done! Now, let's move to Module1.vb and create a bird instance:
Dim bird As Bird = New Bird()
Once you've created an instance of the bird class, write whatever you called the instance, in my case, it is "bird", and add a dot right after it. Visual Studio will then display all of its class methods (you can also invoke IntelliSense by pressing Ctrl + Space):
We now see everything that we can call on the bird instance. The 3 methods we just now implemented are there as well as some others that all objects have from its base.
Now let's create an interface for our bird. We'll use the Interface keyword to do just that. In VB.NET, it's a good practice to prefix the Interface with "I" (as in Interface). Right-click on the project, and choose Add new item -> Interface.
An empty interface will be added to our project. We'll add the headers of methods which this interface will require. The implementation itself, method content, is added later by the class that implements the interface.
Let's add method headers to the IBird interface, we'll purposely omit one of them and only add chirping and breathing:
Public Interface IBird Sub Chirp() Sub Breathe() End Interface
We don't specify the Public modifier since an interface contains public methods only. It wouldn't make sense otherwise since it specifies how to work with an object from the outside.
Let's go back to Module1.vb and change the line with the bird variable so it won't be longer of the Bird type, but of the IBird type:
Dim bird As IBird = New Bird()
What the code above means is that in the bird variable, we expect an object that contains the methods specified in the IBird interface. Visual Studio reports an error since the Bird class doesn't implement the IBird interface yet. Although it does have the needed methods, it must first be informed that it implements this interface. Let's move to the Bird class and let it implement the IBird interface. We do it in the same way as when we want a class to inherit from another, we just use the Implements keyword for that:
Public Class Bird Implements IBird . . .
We also have to specify which methods from the class implements which method from the interface(s). We use the Implements keyword for it as well, this time after the methods definitions. The Bird class will now look like this:
Public Class Bird Implements IBird Public Sub Chirp() Implements IBird.Chirp Console.WriteLine("♫ ♫ ♫") End Sub Public Sub Breathe() Implements IBird.Breathe Console.WriteLine("Breathing...") End Sub Public Sub Peck() Console.WriteLine("Peck, peck!") End Sub End Class
When we go back to Module1.vb, the line with the variable of the IBird type no longer causes an error. The Bird class correctly implements the IBird interface. Meaning that Bird instances can now be stored in variables of this type.
Now just for completeness' sake, let's see what happens when we remove a method from the class, which is required by the interface, like the Chirp() method. Visual Studio will warn us that the implementation is not complete. Once you have visual confirmation of the interface's dependency on the class, put the method back where it belongs.
Let's write bird with a dot after it. Again, Visual Studio will offer the following methods:
We can see that now we can call only the methods provided by the interface on the instance. That's because the bird is now a variable of the IBird type, not the Bird type. Meaning that we cannot call the Peck() method because we did not add it to the interface.
Why did we leave it out in the first place, you may ask? Lots of potential reasons, we've already encountered one of them. By using an interface, we simplify a complex object and expose only the parts needed in a certain part of the program.
Also, I must add that interfaces cannot be instantiated. In other words, this code will not work:
' this code won't work Dim bird As IBird = New IBird()
Multiple inheritance
Visual Basic .NET, like most programming languages, doesn't support multiple inheritance. Meaning that we can't inherit one class from more than one other class. Mainly, because method naming collisions could very well occur when multiple classes containing methods with the same name inherit their methods into another class. Multiple inheritance is often worked around using interfaces because we are allowed to implement as many interfaces in a class as we want. A class of the sort only allows us to work with its instances in ways that we want to. We wouldn't have to worry about of what object type it actually is, or what it provides beyond the interfaces.
Now let's add an ILizard interface to our project. Lizards will be able to breathe and crawl:
Public Interface ILizard Sub Crawl() Sub Breathe() End Interface
Next, we'll try "multiple inheritance", more accurately, implement multiple interfaces by a single class. We'll add a Pterodactyl.vb class to the project. It will implement IBird and ILizard interfaces:
Public Class Pterodactyl Implements ILizard, IBird End Class
If we hover the mouse above each interface, i.e. click on ILizard or IBird, there is a "light-bulb" shortcut to Implement the Interface in the context menu. It may also happen automatically when you write an interface name to implement. Visual Studio will then automatically generate the necessary class methods.
After having both interfaces implemented, the code will look like this. Notice that there are 2 Breathe() methods since the method is required both by IBird and ILizard:
Public Class Pterodactyl Implements ILizard, IBird Public Sub Breathe() Implements ILizard.Breathe Throw New NotImplementedException() End Sub Public Sub Chirp() Implements IBird.Chirp Throw New NotImplementedException() End Sub Public Sub Crawl() Implements ILizard.Crawl Throw New NotImplementedException() End Sub Private Sub IBird_Breathe() Implements IBird.Breathe Throw New NotImplementedException() End Sub End Class
Since the breathing will be always the same, let's remove the IBird_Breathe() method and add IBird.Breathe after the Implements keyword of the first Breathe() method.
Now all we have to do is specify what we want each method to do:
Public Sub Breathe() Implements ILizard.Breathe, IBird.Breathe Console.WriteLine("I'm breathing...") End Sub Public Sub Crawl() Implements ILizard.Crawl Console.WriteLine("I'm crawling...") End Sub public Sub Chirp() Implements IBird.Chirp Console.WriteLine("♫ ♫♫ ♫ ♫ ♫♫") End Sub
That's pretty much it! Now, let's add an instance of the Pterodactyl class in Module1.vb:
Dim pterodactyl As Pterodactyl = New Pterodactyl()
Make sure, that it has both the bird and lizard methods:
We'll stick to interfaces for a little while since there is much more to them that we haven't covered. In the next lesson, Type casting and object hierarchy in VB.NET, you will learn more advanced techniques of the object-oriented programming.