3

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.

3

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.

2

The "something like this instead" approach won't even work:

If you pass a Player interface to a function, the function will not have access to the Character, or the Actor, or the Entity functionality. Presumably the Entity contains very important stuff, like the location of the entity in the world, so you will have a Player in your hands and you won't be able to tell where in the world it is.

Your initial approach is a very good way to go.

Interface hierarchies paralleled by object hierarchies are quite common. For example, see java's collections interfaces and implementing classes. The NavigableMap interface extends the SortedMap interface, which in turn extends the Map interface. (And in languages which are slightly better thought out, like C#, the Map interface does not shy from extending the Collection interface.) It is perfectly fine and very usable.

Amendment

If you would like to examine an alternative approach, consider studying the object model of Unity, which is not so heavily based on object inheritance and interface hierarchies, and instead uses the concept of components. Here is an introduction: http://gamedevelopment.tutsplus.com/articles/unity-now-youre-thinking-with-components--gamedev-12492

  • The initial approach is not the only way to go. It's possible to make the second approach work with generics: public <T extends Entity & Actor & Character & Player> void foo(T player); The signature is more verbose, but otherwise it's not any more complicated to implement or call foo; the implementation can use all the methods from all four interfaces and the caller can pass a BasePlayer (or any other class implementing the interfaces) without any hassle. – Doval Feb 25 '15 at 14:19
  • 1
    »Interface hierarchies paralleled by object hierarchies are quite common« But that says nothing about, whether such duplication makes sense in every case. – Thomas Junk Feb 25 '15 at 14:53
  • @Doval wow, I have never used that syntax, (I just barely know it exists,) so there is not much I can say about it, other than that there may be very good reasons why it is very infrequently used. But I'd be willing to experiment with it, in order to find out for myself. – Mike Nakis Feb 26 '15 at 0:29
  • @ThomasJunk First of all, I do not see any duplication. Secondly, I cannot speak for every case. I can speak of most cases of hierarchies that I have come across, and I can speak about the particular hierarchy that you seem to have in your hands. In any case, I changed the "only way to go" wording, as it was overly stubborn on my behalf, and I amended my answer to provide you with an alternative approach. – Mike Nakis Feb 26 '15 at 0:40
  • The second approach with »components« looks in my eyes promising is a better way than cluttered interface/object -hierarchies. – Thomas Junk Feb 26 '15 at 8:32
0

I have to imagine that your first way, that is, where BaseActor extends BaseEntity and implements Actor, would be the preferable choice. Having your implementations extend an implementation of the parent interface would allow you to reduce code duplication, since, for example, BaseActor can inherit basic implementations of the methods in Entity from BaseEntity. If there's no reason to change what they're doing from how they're defined in BaseEntity, why redefine them again and again in every class in the hierarchy?

0

This depends on what methods are on Player and whether or not you would have to add methods which are better on other interfaces.

E.g. getName(). If you want to call getName() on a Player, you would need to define the method there as well as in Character.

If this isn't the case then you should question whether Player //is a// Character after all.

Overall it is best if your classes model the domain properly and I would only break the hierarchy if it isn't really in the domain (if a Player isn't really a Character).

An example of when this might happen is when an inheritance exists just to save code.

For example, you may want a Vehicle which can drive so you extend BaseActor to get some of the action behaviour when really a car is just an entity as it is the Actor using it that has does actions. (So you should probably compose an Actor inside your Vehicle which extends BaseEntity).

  • Character is the parent of both Player and Npc. Both have a name (and thus Character has a getName() method), and Npc also has a getId() method. – Zymus Feb 25 '15 at 7:52
  • Then it definitely looks like the interfaces should be in a hierarchy. You won't make things easier for the implementers by trying to hide the relationship between Character and Player. – ashirley Feb 25 '15 at 7:55
0

I would go for another approach:

Interfaces are meant to share behaviour accross otherwise independent or different objects. E.g. if you have an Interface called swim it could be implemented by humans or by ducks. Ducks and humans have not that much in common, but: the could swim; and if you look at how humans and ducks do it - they use a different approach, or implementation. So if you are dealing with humans and ducks it makes totally sense to use an interface. This is called the strategy pattern.

If you want to express, that the subjects of some behaviour have something in common, you could use class(ical) inheritance or as the books say an: »is a«-relationship.

So far the theory.

Looking at what you posted, you have several interfaces:

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

Entity: Something in the game world

Actor: An Entity that can perform actions

Character: An Actor that has a name (as well as some other features I haven't determined yet

Player: A Character that is played by a human being.

Your classes are BaseEntity, BaseActor, BaseCharacter,BasePlayer.

You are mirroring your class definitions in the interface definitions. Here, you are saying something like the following: »An Entity is, what has entity-behaviour« Only to some extend, that does make sense. That is, what I expect from an entity.

Based, from what I said, that different objects share behaviour via interfaces, your decision seems at best undecided:

1) If you choose to use a hierarchical approach via inheritance (is-a), there is no need to back up every class with an interface. You have similar objects (an actor is an entity with some extras, a character is in principle an actor with some extras). If you need specification, you typically subclass.

2) Or you choose the "behaviour via interface"-approach, where you define behaviour (and perhaps groups of behaviour) but need no classhierarchy.

But not both.

Your second approach goes in that direction of (2).

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 { }

Better:

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

public class EntityImpl implements Entity { }
public class ActorImpl implements Actor { }
public class CharacterImpl implements Character { }
public class PlayerImpl implements Player { }

With this, you make the following points clear:

1) For each class, you strictly define the API ("interfaces as contracts"): A »character« is some object, which behaves at least like a "Character"

2) Since Character extends Actor, you are saying, that characters in some respect behave like actors

3) If I want to design an entity with extras, I could do so in using the existing interface and create a new class implementing it and adding new behaviour (perhaps via another interface). So the interfaces are reusable.

Of course, there is some drawback: Interfaces have to be implemented with each class (exception: default methods). But on the other hand, you see every method(_implementation) without walking up the inheritance-tree.

You could go either ways, class hierarchy or interface hierarchy. In terms of maintainability and flexibility, I would go for the second solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.