Struggling to understand interfaces

First off, I’m a bit of a unity noob and still learning a lot of the basics.

Up till now I’ve used inheritance for my classes, and I’ve recently learned of interfaces. However, no matter how many posts I read I cannot see their proper use. I just don’t understand how they are necessary, and I think this is because I don’t really know their power.

In my project I have now split my used to be “CharacterBaseClass” into various components (HP, Atk, Atk Speed etc. all holding variables, and methods). I don’t understand how interfaces could be of any help to my system, yet apparently they work wonders with a component based approach. It’s my understanding that if I make an interface IShootable, for instance, I can declare methods within it that must be called in any classes that ‘inherit’ said interface. So let’s say my IShootable contains a Shoot () method… Now any class that inherits this interface has to include this method, but that method has individual actions for each separate class is attached to. I fail to see how this is useful, as it is surely just extra lines of unnecessary code. I understand the problems that you can run into using class inheritance with conflicting inheritance types etc. but then what is the difference between: writing a Shoot () method in every Class that uses it, and: writing an interface including Shoot () and then attaching this interface to each component that can shoot, and then writing the code for the method anyway.

What am I missing here? Can someone please enlighten me as to how interfaces can properly be used in a component based project search as mine? Please try to simplify as much as possible as I have read various threads and followed tutorials and they still haven’t cleared it up for me.

Many thanks in advance

Interfaces are just inheritance. Suppose you have this:

Shooter s1 = GetComponent();
if(s1!=null) s1.shoot();

s1 could be an actual Shooter, or something that inherits from Shooter. In the second case, Shooter could be an interface.

Interfaces are really just a work-around. C# banned multiple inheritance, but then used interfaces to add it back. They’re simple once you stop thinking of them as some new thing. You’re just inheriting functions from them. My longer explanation is in taxesforcatses, intro programming link, inheritance examples chapter, section 4 (but it’s based on the stuff that came before it, so not as good standalone.)

As for why you can’t just add Shoot() to whatever you need, how would the rest of the program know it can call Shoot? That’s what inheritance is for.

Thanks for the reply, kind of makes sense to me. With the Shoot() example though, I have a projectile gun, and a raycast gun both with Shoot() methods (named differently). They get called when fire == true, which in my case is when the right virtual joystick is used. How could I/ and why should I use interfaces to call these functions?

You can view an interface as a contract between two layers which helps to hide unnecessary implementational details. And sometimes, it can also serve as the most basic building block in a system, which is designed with OOP principle.

It helps you to take an abstract, top down approach when you design your system, and also make it more flexible as it can remove redundant couplings between components.

In designing a system, I often lay down the most important concepts, like ‘player’, ‘inventory’, ‘item’, ‘location’, and etc, for instance, and define each of them as an interface because we don’t know anything about how we should implement them.

Then I think about what could be the role and responsibilities of each interface, and write them as either properties or methods. Ideally, you can already see the overall picture of how each component can interact with each other at this stage.

Then finally, we can finally start with the implementation. And during that, we might find such cases where there are two or more way to satisfy the requirements specified by the interface, but as long as every clients only reference the interface, rather than any specific implementations directly, you don’t really have to worry about it.

And interface is a tool for an abstraction, so if you make a game when you can shoot an enemy or an object like a wall, for example, you can try to generalize the concepts into such an abstract concept as ‘something destructible’, which can be represented by ‘IDestructible’ interface which both your Enemy and Wall classes implement. Then if you define such a method like ‘Damage(force: float)’ in IDestructible, you don’t have to worry about any details about what target your bullet hits, for example.

It’s true that interfaces in such languages as C# where you can’t use mixins, their usefulness might be severely limited. But still, I believe they have their use in such environments, especially if you are intended to build a library or a framework of some sort.

Interfaces are incredibally useful. Here are a couple of use cases.

One: When you want two different components to respond to the same type of stimulus. For example you have a bunch of things that can all be clicked on. A banana, the terrain, the enemy, and a menu item should all behave very differently when clicked on, it makes no sense for them to inherit from a common class. But having a common interface lets them all be handled the same way by your input code.

Two: Interfaces aid decoupling. Dependencies are unavoidable. But by being dependent on an interface instead of a concrete class, you can make it easier to change things at a later date. This also allows you to have swappable components, for example an AI controller and a player controller.

Three: Interfaces are useful for limiting access to functionality. By handing out limited interfaces, you can limit what access the client class receives. If you hand out a reference to a MonoBehaviour, that will include the capacity to access the GameObject, the Transform, and a bunch of other stuff that might not be relevant. By handing out an interface you can limit access only to stuff that’s relevant.

1 Like

Interfaces are a way to add behaviour, kind of like Components/MonoBehaviours, except the behaviour will be unique each time (meaning they require new code (implementation) for every class that uses it). Unity components are a shared behaviour.

If a bunch of classes/components implement the interface you can guarantee they have those functions/properties/etc. Useful, because you don’t have to know anything about the class :sunglasses:. Not so useful, because you don’t know anything about the class :rage:, and you can’t use any nice Unity things like GetComponent/transform/etc when working with an interface variable.

Components can often cover most of your bases, if you make them tweakable enough.

Bad
class.Shoot();
otherClass.Shoot();
anotherClass.Shoot();

Better (if Class, OtherClass and AnotherClass implemented IShootable)
shootable.Shoot();

You don’t need to know which class it’s from. You can execute them all with the same code. You can also add these shootables to the same list/array, because they are the same type.

If you find yourself copy & pasting the same code into different interface implementations, it’s time to inherit, or use a component, because they are for shared information. You could even call a component from an interface function to get the shared functionality, but the GetComponent would still be copy/pasted code.

For Shootable/Shooter, this is what I would do:

  • If everything shoots in the same way, use a component.

  • If everything shoots in a similar way, use a component with enough variables to tweak it (so you can have pistol bullet and shotgun spray in the same script).

  • If most things shoot in the same way, but a few are unique, inherit the component and override the Shoot().

  • If everything shoots in a completely unique way, use interface.

And let’s not even get into Abstract Classes…

P.S. I’m an artist turned programmer, so I could be wrong.

GetComponent works with interfaces, and has done from somewhere around 4.6

This isn’t really a proper way to think of interfaces. They aren’t really inheritance, they are simply a contract that says “any class implementing this interface will have these methods/properties, regardless of their implementation, and thus they must be available for you to call on this class”. Interfaces require you to still manually implement these methods on any classes that implement the interface, which implies there’s no real inheritance going on there, as there is no “base” method to call from.

Interfaces make it simple for many different classes to share common implementation details so that parent class type is irrelevant, so you only need to get say… the “ICanDie” interface on any object/class (so long as it implements ICanDie) and call the “Die()” method and the class will kill itself, even though each of those classes could have their Die() method doing different things.

Not true actually! Because of this great thing we have called “Properties” :slight_smile: Your interface can implement a Property, for example:

public interface TestInterface
{
    Transform Trans{
        get; set;
    }
    float Speed{
        get; set;
    }
    bool CanFly{ //Return or set whatever variable/method will hold/handle this value on a class
        get; set;
    }
    StatsClass GetStats{ //Return a class of type StatsClass that would contain any stats for a given class
        get;
    }
}

public class StatsClass
{
    public float health = 5f;
    public float defense = 2f;
    public int level = 20;
}

Now you have a property that will have to be implemented on any classes that implements this interface, and you will make that property return or get from a Transform variable that is local to the parent class or classes it actually inherits from. Or you could even have the property call some method in your class too, whatever you want. It’s yours to implement how you like.

Here’s a quick example implementing that interface, separate scripts:

public class RandomCharacter : MonoBehaviour, TestInterface
{
    private StatsClass stats = new StatsClass();
    private float speed = 1.3f;
    private bool canFly = false;
    private Transform trans;

    public Transform Trans{
        get{return (trans != null) ? trans : this.transform;}
        set{trans = value;}
    }
    public float Speed{
        get{return speed;}
        set{speed = Mathf.Clamp(value, 0.1f, 5f);}
    }
    public bool CanFly{
        get{return canFly;}
        set{canFly = value;}
    }
    public StatsClass GetStats{
        get{return stats;}
    }
}
public class SomeRandomScript : MonoBehaviour
{
    public GameObject someObj; //Game Object that has any class that implements our interface

    void Start()
    {
        if(someObj != null)
        {
            TestInterface test = someObj.GetComponent<TestInterface>();
            if(test != null)
            {
                ProccessTestInterface(test);
            }
        }
    }

    public void ProccessTestInterface(TestInterface test)
    {
        Debug.Log(test.CanFly);
        Debug.Log(test.Speed);
        Debug.Log(test.Trans.position);
        Debug.Log(test.GetStats.health);
        Debug.Log(test.GetStats.defense);
        Debug.Log(test.GetStats.level);
    }
}
1 Like