Getting Started with Interfaces (Unity and C#)
Until fairly recently, I didn’t exactly understand what interfaces are or why we should care about them when programming. I could see that they essentially force us to add specific methods or properties to our classes, but I didn’t see why this would be useful beyond encouraging us to set up our classes consistently. I’ll try to give a bit of an introduction to them here, and will express just how useful these are by the end of the article 😉
Start
The way I’ve been taught to think about them is that they’re a sort of “contract” within our code, so that when we implement an interface we are guaranteeing that it contains the methods and/or properties outlined in the interface. Let’s take a look at a very simple interface:
We can declare an interface in a similar way to how we declare a class, just swapping “class” with “interface” and (in Unity at least) removing the Monobehaviour class inheritance. This particular interface only has one member method to it (“Damage()”), meaning any class which implements this interface will need its own, local Damage method (which takes the same arguments or lack-of-arguments in this case).
As a quick aside, a naming convention with interfaces is that we prefix them with a capital “I” followed by PascalCasing for a word ending with “-able” — for instance, IKillable, IDamageable, IHealable, IInteractable, etc. You of course don’t need to follow this convention but I thought I’d just mention it here in case it helps 😉
Implementation
To implement an interface, all you need to do is add a comma after your class declaration then add the desired interface. You’ll then need to ensure your class contains what the interface says it should contain:
Since this Bat_Enemy class implements a “Damage()” method as specified in the IDamageable interface it uses, the compiler shouldn’t throw any errors at this. We’ve successfully made use of this interface, and we could easily use this same interface elsewhere in our code:
Even though the Crate and Bat_Enemy classes could be poles apart in terms of their behaviour and even their use of the Damage method, they nonetheless both meet the terms of the IDamageable “contract”.
Use
The main usefulness of an interface probably comes in this: by looking for and accessing an interface, rather than a specific class, we can call a method on a class without needing to know what that class is. Let’s do a quick comparison:
In this example, we’re having to check for specific classes in order to call their local Damage methods. In order for this to work, we need to maintain/update a long list of classes the player can damage, pointing to an object of a particular class each time. Now assuming all of these classes where to implement the IDamageable interface we created, let’s see what that code looks like:
And that’s it. The Player class doesn’t need to care or even know about what it’s damaged specifically, just that it needs to have the IDamageable interface. This is only achievable because of that guarantee or contract we touched on: whatever the class, so long as it implements the IDamageable interface, we know it must have a Damage method and as such we know we can can call “Damage()” on it.
As a result, we’d no longer need to update the code in our Player class every time we need them to be able to damage a new class. This can make scripts like our Player class incredibly versatile, and likewise the IDamageable interface could be quickly and easily applied to any of our custom classes (and we don’t even need to worry/know about the details of a class’s specific implementation of the Damage method).
If you feel you’ve got a good grasp of interfaces, I’d highly recommend giving them a try in your projects as well as looking into the Object-Oriented Programming concept of “Polymorphism”. It’s a term I heard a lot of when I was starting out with C#, but I only now feel like I understand it after having worked a little with interfaces.