views:

187

answers:

5

I'm making a game where each Actor is represented by a GameObjectController. Game Objects that can partake in combat implement ICombatant. How can I specify that arguments to a combat function must inherit from GameObjectController and implement ICombatant? Or does this indicate that my code is structured poorly?

public void ComputeAttackUpdate(ICombatant attacker, AttackType attackType, ICombatant victim)

In the above code, I want attacker and victim to inherit from GameObjectController and implement ICombatant. Is this syntactically possible?

+2  A: 

It is only syntactically possible if GameObjectController itself implements ICombatant; otherwise, I would say you have a design problem.

Interfaces are intended to define the operations available on some object; base classes identify what that object is. You can only pick one or the other. If accepting the ICombatant interface as an argument is not sufficient, it might indicate that ICombatant is defined too narrowly (i.e. doesn't support everything you need it to do).

I'd have to see the specifics of what you're trying to do with this object in order to go into much more depth.

What if you did this instead:

public class GameObjectControllerCombatant : GameObjectController, ICombatant
{
    // ...
}

Then derive your combatant classes from this instead of directly from GameObjectController. It still feels to me like it's breaking encapsulation, and the awkwardness of the name is a strong indication that your combatant classes are violating the Single Responsibility Principle... but it would work.

Aaronaught
I could just make `ICombatant` have a getter for a `GameObjectController`, but that seems like unnecessary bloat. The code would always be `public GameObjectController Controller {get {return this;} }`
Rosarch
@Rosarch: If it's actually possible for the `ICombatant` interface to implement such a property then it would seem to indicate that `GameObjectController` does in fact already implement `ICombatant` (or could be made to); therefore, just accept a `GameObjectController` argument, you don't need the `ICombatant`.
Aaronaught
Thinking this through further, your predicament may indicate the opposite of this; that the classes that implement `ICombatant` have way too many responsibilities. It doesn't seem to follow logically that an `ICombatant` is actually the *same instance* as a "controller." I'd really like to see the code that you would hypothetically write in the method body if this were possible to do in the signature.
Aaronaught
+4  A: 

Presumably all ICombatants must also be GameObjectControllers? If so, you might want to make a new interface IGameObjectController and then declare:

interface IGameObjectController
{
    // Interface here.
}

interface ICombatant : IGameObjectController
{
    // Interface for combat stuff here.
}

class GameObjectController : IGameObjectController
{
    // Implementation here.
}

class FooActor : GameObjectController, ICombatant
{
    // Implementation for fighting here.   
}
Mark Byers
This is exactly what I want, except `GameObjectController` is a class, not an interface. Is there any way to do this with a class, or must I restructure it into an interface?
Rosarch
@Rosarch: You need to restructure. It's a well-known refactoring operation called 'Extract Interface' and can be performed automatically. You can also do it by hand very easily. http://msdn.microsoft.com/en-us/library/fb3dyx26.aspx
Mark Byers
+1  A: 

Well, sort of. You can write a generic method:

public void ComputeAttackUpdate<T>(T attacker, AttackType type, T victim)
    where T : GameObjectController, ICombatant

That means T has to satisfy both the constraints you need. It's pretty grim though - and if the attacker and victim could be different (somewhat unrelated) types, you'd have to make it generic in two type parameters instead.

However, I would personally try to go for a more natural solution. This isn't a situation I find myself in, certainly. If you need to regard an argument in two different ways, perhaps you actually want two different methods?

Jon Skeet
+4  A: 

I'd say it probably indicates you could restructure somehow, like, have a base Combatant class that attacker and victim inherit from, which inherits from GameObjectController and implements ICombatant.

however, you could do something like

ComputeAttackUpdate<T,U>(T attacker, AttackType attackType, U victim)
      where T: ICombatant, GameObjectController
      where U: ICombatant, GameObjectController

Although I probably wouldn't.

Jimmy
A: 

I would go for generic as Jimmy above suggest. Personally, I like generic methods.

vittore
You should just upvote his answer then and perhaps leave a comment to his answer.
Mark Byers