Java – Implement multiple separate interfaces or interface hierarchy

interfacesjava

I've been refactoring one of my projects recently and ran into a decision I have to make.

I have several interfaces:

  1. Entity: Something in the game world
  2. Actor: An Entity that can perform actions
  3. Character: An Actor that has a name (as well as some other features I haven't determined yet
  4. Player: A Character that is played by a human being.

The type hierarchy is currently

public interface Entity { }
public interface Actor extends Entity { }
public interface Character extends Actor { }
public interface Player extends Character { }

The reason I have it designed this way is because a big portion of functionality will come from community-driven mods that add functionality to the game, and I want it to be as modular as possible.

Now, the decision I ran into is: Should I keep this type hierarchy, or, to allow for more robust design (possibly, I can't think of an example), implement each individually?

The current implementation details are

public class BaseEntity implements Entity { }
public class BaseActor extends BaseEntity implements Actor { }
public class BaseCharacter extends BaseActor implements Character { }
public class BasePlayer extends BaseCharacter implements Player { }

My question is, would there be any benefit (from a design perspective) of doing something like this instead

public interface Entity { }
public interface Actor { }
public interface Character { }
public interface Player { }

public class BaseEntity implements Entity { }
public class BaseActor implements Entity, Actor { }
public class BaseCharacter implements Entity, Actor, Character { }
public class BasePlayer implements Entity, Actor, Character, Player { }

I can't think of a good reason to do this, but someone who would use my API to make their own mod may have their own

public class FooPlayer implements Player, Foo { }

And not want/care about the methods defined in Entity, Actor, or Character.

Best Answer

The decision to make an interface extend another should be based on the Liskov Substitution Principle. So Actor should only extend Entity if every program that's correct when given an Entity will also be correct when given an Actor. If it's not always the case that an Actor can implement everything an Entity should implement, then keep them separate. See also the Interface Segregation Principle.

If you decide to keep the interfaces separate, you'll need to use generics whenever your methods need an argument that implements multiple interfaces. E.g.

public <T extends Entity & Actor> void foo(T entityActor) {
    entityActor.someEntityMethod(); // OK
    entityActor.someActorMethod(); // Also OK
}

The only cost here is the verbosity of the signature, but otherwise it's not any more difficult to implement or use:

BaseActor actor = getActorFromSomewhere();
foo(actor); // Just works

In the case of seperate interfaces I would also recommend choosing composition and delegation over inheritance as illustrated in Thomas Junk's answer. Inheritance hierarchies are brittle and rigid; using composition and delegation it's easy to mix and match implementations of the different interfaces.