Too many interfaces?

Hi there, I have previously asked a design question related to interfaces (Link here). I have now another question when it comes to interfaces. When have you implemented too many interfaces?

Implementing multiple interfaces with few public methods:

My current design involves multiple interfaces. An example could be:

public interface ITarget
{
    void OnTargetChange();
}

public interface IDeath
{
    void OnDeath();
}

public interface IVisibility
{
   void OnVisibility();
}

When implmenting this, it will look something like this:

public class Player: Monobehaviour, ITarget, IDeath, IVisibility
{
   public void OnTargetChange(){}
   public void OnDeath(){}
   public void OnVisibility(){}
}

Implementing a single interface containing multiple methods:

However, this same design can be achieved by creating a single interfaces that implements all the methods at the same time.

public interface IEntity
{
   void OnTargetChange();
   void OnDeath();
   void OnVisibility();
}

And when implementing this

public class Player : Monobehaviour, IEntity
{
   public void OnTargetChange(){}
   public void OnDeath(){}
   public void OnVisibility(){}
}

My question is this, what good rule of thumbs are there to follow? When is a single interface too big or too small. My personal opinion is implementing multiple interfaces with only few public methods, because thats how you achieve the highest level of loose coupled code, however the downside of this is you have to make multiple if-statements in order to determine whether a class have implemented all the different interfaces. All the if-statements can be minimized if you implement a single interface containing all the different public methods.

What is your thought on this, what rule of thumbs do you follow?

I think the discussion might be hampered by the example you’ve chosen. It’s seems that in this particular case interfaces are being used to receive events. This is perfectly fine and was (is?) the way that JWT events worked in Java if I remember correctly, but it’s unnecessary (and perhaps even wasteful) in .NET because events and delegates are built into the language and more flexible constructors.

A better example would be an IPowerUp interface or an IEnemy interface. The actual methods of each interface will vary depending on the game and on your needs, but I would have a very hard time decomposing those into smaller interfaces in a way that would make any sense.

Basically, if you treat interfaces as their name suggests, i.e. the exposed pins of a black box that has an object inside it, I think you’ll find that the number of pins (read: methods) and the function of each pin will more or less be self-evident.

Alright, I think I get your point, but I have an additional question then. In order for clarification, i provide with another example. Lets state we have both Enemies and Friendlies in our game. In our situation, both friendly and enemies have the ability to die. My approach to implement this would be to create an IDeath interface instead of two seperate interfaces IEnemy and IFriendly both implementing an OnDeath method. To me, this seems to be the most natural approach.

Alrighty, I think I have stumbled upon something called Interface Inheritance which possibly resolves this issues.
So in my above example, I could implement an interface called IDeath.

public interface IDeath
{
   void OnDeath();
}

Then, if I create both IEnemy and IFriendly then both of these can inherit from the IDeath interface.

public interface IFriendly : IDeath
{
   void CallForHelp();
}


public interface IEnemy : IDeath
{
   void ChaseTarget();
}

When implementing these into a class

public class FriendlyBob : Monobehaviour, IFriendly
{
   public void CallForHelp(){ }
   public void OnDeath(){ }
}

public class EnemyBob : Monobehaviour, IEnemy
{
   public void ChaseTarget(){ }
   public void OnDeath(){ }
}

How about this? :smile:

public interface IDeath {}
public interface IFriendly : IDeath {}
public interface IEnemy : IDeath {}

/E: To slow. ;o

Why interface for those?

You can do class inheritance too;

public abstract class Character : Monobehaviour
{
    public void OnDeath() { }
}

public class Enemy : Character
{
    public void ChaseTarget() { }
}

public class Friendly : Character
{
    public void OnDeath() { }
}

The use of an interface is to give similar method contract to class that has nothing in common. If they are similar to each other, they may share a base class.

I’m assuming that by OnDeath you mean the method what will called when either a friendly or an enemy need to die. I think calling it “Die” would be a better name in that case.

The methods might have the same name, but I think you’ll agree that, in most games, an Enemy dying will happen under conditions that are very different from those of a Friendly dying, with different code paths calling either method and different implications of both.

In that case the commonality is in name only, and having two different Die methods is the more correct solution (IMO at least).

But maybe you’re building an RTS game like the Total War games, and every soldier in the arena, whether friend of foe, shares very similar logic and behavior with the others. In this case it would probably be better to replace both IFriendly and IEnemy with a single called IUnit. The faction can be a field in that interface, and the look of the unit can be determined by the implementation. Still no place for an IDeath interface in this scenario.

Or maybe you have yet a different scenario where Enemies and Friendlies are different enough that it doesn’t make sense for them to share a common interface, yet they share a sliver of common behavior that requires them to be treated as if they are the same kind of object in some scenarios. Then, as you’ve just discovered, interface inheritance is a better option. Though you might want to change the name of IDeath to something that indicates the capability of the object implementing the interface, such as IDyable or IMortal (since it can die, but it’s not Death incarnate :)).

currently i use “idamage” interface in my game, and am planning to use it with other damagable objects in world, and not only regular enemies.

this interface shared with all enemies , friendly units, even objects.

public interface IDamage
{
   bool IsEnemy();
   bool IsDamagable();
   void Damage(float damage);

}

it’s the most useful approach for me so far …
i can get a small feedback whether this object is an enemy or if it is currently damagable (in case if objects applies some protection) then if all confirmed, i apply Damage()

There is no good rule or “golden bullet”, each design decision should be based on real needs and reflects defined abstraction. If you want to achieve really loose coupled architecture, you should consider about using Component Based approach which also supported by Unity, because until you’re using interfaces you always will have dependency on it (see. Fragile binary interface problem)

Boom! Buttload of replies. So based on all these replies, what I have understood is:

My idea on how and when to optimally use interfaces is slightly faulty. My idea was to use interfaces for most communication between classes in order to achieve the most loosely coupled code as possible, however it appears that interfaces should be used for scenarios where two distinct classes, can communicate with each other in a loose way.

However, I still have a few questions then:

I get your idea, however, without the usage of interfaces, wouldn’t such a design create strong coupled coding? Lets imagine, that our enemy jumps into a trap and the OnDeath method is to be executed. The trap class would require a reference to the Character base class or child class, in order to execute the OnDeath method, which allows the trap class to only kill characters and its childs. However, if we wanted to “Kill off” something else than a Character, lets imagine a Pet class, wouldn’t an interface be a better solution, allowing the trap class to kill something which have implemented the IDeath (or IDyable based on shaderops suggestion ;)) interface, making the trap class indepedent of the Character class.

Alrighty, based on your reply, I see I must think more through what the actual Die methods is going to look like, and what they execute.

I like your example, and so far, it is the one that makes most sence to me (I am an example kind of guy). I will clearly try to take your example into account, when implementing interfaces.

I have just glanced at "Fragile binary interface problem" though, this appears to be a bit above my level of understanding within programming. If you have any examples lying, or resources of where I can better understand this, feel free to share, because I am finding it difficult to see how you can perform even more loose coupled coding than using interfaces. (I guess it will come to be, when I have investigated the problem even more, or played around with interfaces some more).

Don’t try to uncouple everything.

I would not implement an IDeath interface to the Character, because it would make no sense that any other class would “die”. A Crate or a Door would not die. There’s no point to a interface if only one class uses it.

A character base class can be useful here; every character has HP, a weapon, pathfinding, etc. They can all die, be healed, or attacked. It makes senses to package all those properties and behaviour in the same class, and then derive from it to implement specific cases.

I would probably go with a IDamage interace with a method that receive a float or a hint, and maybe an enum of what damage type it is. I would leave it to the class implementing it to decide how to react to the damage received. Then all class that can be attacked (Door, Crate, etc.) can implement it.

Since it’s uncouple, also assume the message past must also be uncoupled and as generic as possible. IDeath is quite explicit and leave little space in its definition… It kills something, which means it’s something alive!

The IDeath interface is properly not the best example, because this basically covers all living things, but lets imagine an IInteractable interface instead.

But isn’t it good practice to actually uncouple everything from the start? I agree with you, if an interface is only implemented once, then it would not make sence to actually create the interface, however, making it an interface to begin with, you have the option later on in the development to change your mind, and develope new classes that use this interface? A base class would be still applicable, though the base class could implement this interface, and if other non-character classes later one is to be developed, you can implement the IInteractable interface aswell.

So in short, by making everything loose coupled from the beginning you prevent upcomming problems.

Im not quiet sure what this does have to do with our interface architecture in .net. In the first instance, this has nothing to do with our commonly used interfaces. The problem does only describe a problem common to MOST OOP programming languages and does explain how code might break if one changes a dependency. It effectivly, to get to the point, consists of changing the source code of a dependency, messing up its lookuptable in memory and therefore breaking anything which previously depended on it since the lookuptable is now incorrect. However, such a problem does not exists in .net since it writes out its full table as meta data to be dynamically used.
Note that the fragile binary interface problem is often confused with the “Fragile base class problem”, which infact does explain a quiet other problem.

I don’t try to get everything perfect up front. I accept that I’ll be spending time changing things later on that didn’t end up exactly like I planned at the start. With that in mind, there’s a happy medium between “gets the job done” and “perfect” that I like my code to sit at. If the code only scrapes by as functional then it costs me more time to change later because it turns into unmaintainable spaghetti, but on the other hand I don’t want to spend time now getting something perfect if I’m not 100% sure it’ll be sticking around - and you only know what’s going to ship when you push your game out the door. :wink:

So, with an interface, if I can’t think of why I’d want to reuse something I just make it a part of the initial class I want it for. If I do later find an extra use, I’m pretty disciplined about going back and splitting it into an interface - it doesn’t take that long, so it’s no great loss. Compare that to the amount of time I might end up spending if I try to plan for every eventuality that might occur… and then throw the code away later because I changed my mind about my game’s design…

Don’t use language features like inheritance, interfaces, delegates, etc. etc. because it’s “best practice” or whatever. Use them because and where they save you time over the lifetime of a project.

1 Like

I fully understand what you are saying, and here my lack of experience must be taken into account. When will the savings of implementing an interface become overruled by the consumed time it takes to implement it. But I guess this will come with time as I get more experience. Your statement

“If I do later find an extra use, I’m pretty disciplined about going back and splitting it into an interface”

is properly the best advice from you, and I guess I just have to try something out, and if it doesn’t work out the way I want it, i should be disciplined enough to go back and correct it, instead of making everything perfect before hand.

IInteractable is also a bad example, because it’s not a communication channel. Let’s say you make a game where the player can click on something and interact with it; characters, chest, switch and so on. Obviously, you will want to feedback than the object can be interacted with, some FX, maybe a light. You will want some icon on screen. You might also want some localization that name that object and give it a description…

At that point, you better use a Interactive component that store all that information.

From that point, you have to ask yourself… Is it the Interactive component that call other, or is the interaction an event?

public class Interactive : MonoBehaviour
{
    public event EventHandler OnInteract;
}

I would probably go with the event because I could hook on it from other things. Let’s say I have a switch that open a door, the door would target the switch and register to the event.

public class Door : MonoBehaviour
{
    public Interactive switch;

    private void Start()
    {
        switch.OnInteract += OpenDoor;
    }
}

No, it does not prevent upcoming problems and can create new one. Preemptive optimization or preemptive over-design might not be the root of all evil, but it sure doesn’t help.

You have lot of different tools and design pattern; hierarchy, composition, components, interface, etc. Each has a specific role and trying to blanket everything with a single one is just bound to give you headache.

I can’t complete grasp what you are saying but I guess thats because I haven’t fully understood my “own” problem yet. I don’t believe I try to use interfaces for everything.

The idea of using an event for handling door opening from a switch is a good approach, and that would also be the approach I would use. However, if the player is going to interact with the switch in the first place, I would implement the IInteractable interface on the switch. So when the player interacts with the switch, through the IInteractable interface, it would execute the event and run all methods referenced in the OnInteract event.

Well that’s the thing, right - interfaces take bugger all time to implement. Same thing with many other tools at our disposal That’s not where the time gets chewed up.

Absolutely. And don’t get hung up on making it perfect. As long as everything you write is better than the last thing you wrote you’re headed the right way.

The real challenge there is in remembering where you (or others in your team) have left those “opportunities for improvement” behind. Good planning, documentation and communication are important here. I find stuff like Jira to be great, even on one-man projects - it’s not just the task list part, but that you fill in your plans or partial plans as you go. It’s a great, high-level way to document progress and planning, so it helps you keep familiar with how the software is growing in a non-code-centric manner.

There’s multiple parts to that problem, though. You don’t have to solve them all in one place.

  1. The player presses a button to “use” the switch. This is an instantaneous thing in response to an input.
  2. The switch somehow communicates to the door that it should open.
  3. The door opens, which probably involves an animation or something like that. This happens over time.

On the weekend I implemented an elevator. It has a GUI popup which opens when you “use” the control panel in the elevator, usable call buttons outside, a behaviour that makes it go up and down to various floors (which are linked to the buttons in the GUI and the call buttons)… Needless to say, it’s broken down into a few simple components and events - it never even occurred to me to try and solve all of that stuff in one place. (Most of which are generic and reusable, as a bonus.)

One thing that’s important is to also think of this beyond the scope of the exact implementation. You’re showing an example of using interfaces for event subscription. There’s nothing inherently wrong with what you’re doing… but just keep in mind that if you make it too granular it gets harder to maintain and read as you don’t always know quickly what functionality comes from what interface so it is good to group them. Here are a couple of additional considerations:

  1. Interfaces can be better than base classes in many cases. The downside is that you can’t define actual functionality in the interface, however C# doesn’t support multiple inheritance (i.e. a single class can only inherit one class at a time). So you end up with a class that inherits a class that inherits another class, etc. Realistically you can actually combine the two though. You can have a base class that implements a couple interfaces and then have your child classes implement the extra interfaces you need. Just do what makes sense for your implementation.

  2. Decoupling needs to be put into the proper context. For example, let’s say you’re building a fighting system and that fighting system. You’ll probably want a mix because you’ll need to define functionality on your end. However, you can also use a series of interfaces to define characteristics of your characters. This makes the asset easier to share between projects because the end user just needs to implement the appropriate interfaces on their objects (i.e. an IMage interface for magic, an IBrute interface, etc…). You can even have them all implement an ICharacter interface and store them in the same list… then your system can use the other interfaces to perform specific actions.

  3. Testability - This is a big one for me. Interfaces make it much easier to mock classes and build out fake objects for testing purposes.