我正在制作一个游戏,其中每个Actor都由GameObjectController
表示。可以参加战斗工具ICombatant
的游戏对象。如何指定战斗函数的参数必须从GameObjectController
继承并实现ICombatant
?或者这是否表明我的代码结构很差?
public void ComputeAttackUpdate(ICombatant attacker, AttackType attackType, ICombatant victim)
在上面的代码中,我希望attacker
和victim
继承GameObjectController
并实施ICombatant
。这在语法上是否可行?
答案 0 :(得分:6)
我想说它可能表明你可以以某种方式进行重组,例如,有一个攻击者和受害者继承的基础战斗者类,它继承自GameObjectController并实现ICombatant。
然而,你可以做类似
的事情ComputeAttackUpdate<T,U>(T attacker, AttackType attackType, U victim)
where T: ICombatant, GameObjectController
where U: ICombatant, GameObjectController
虽然我可能不会。
答案 1 :(得分:4)
据推测,所有ICombatants也必须是GameObjectControllers?如果是这样,您可能想要创建一个新的IGameObjectController接口,然后声明:
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.
}
答案 2 :(得分:2)
只有在GameObjectController
本身实现ICombatant
时,语法才有可能;否则,我会说你有设计问题。
接口用于定义某些对象上可用的操作;基类识别该对象是什么。你只能挑选一个或另一个。如果接受ICombatant
接口作为参数是不够的,则可能表明ICombatant
的定义过于狭窄(即不支持您需要它执行的所有操作)。
我必须看到你正在尝试用这个对象做的具体细节,以便更深入。
如果你这样做了怎么办:
public class GameObjectControllerCombatant : GameObjectController, ICombatant
{
// ...
}
然后从此而不是直接从GameObjectController
派生你的战士类。它仍然让我觉得它正在破坏封装,而且名称的尴尬强烈表明你的战斗员类违反了Single Responsibility Principle ......但它会起作用。
答案 3 :(得分:1)
public void ComputeAttackUpdate<T>(T attacker, AttackType type, T victim)
where T : GameObjectController, ICombatant
这意味着T
必须满足您需要的约束。虽然它非常严峻 - 如果攻击者和受害者可能是不同的(有点不相关)类型,你必须在两个类型参数中使它成为通用的。
然而,我个人会尝试寻求更自然的解决方案。当然,这不是我发现自己的情况。如果你需要以两种不同的方式看待一个论点,也许你真的想要两种不同的方法?
答案 4 :(得分:0)
如果你控制了所有有问题的类,并且GameObjectController没有定义任何字段,那么最干净的方法是定义一个IGameObjectController(其属性和方法与GameObjectController的属性和方法匹配)和一个ICombatantGameObjectContoller(它来自IGameObjectController)和ICombatant)。在需要两个接口的情况下可以使用的每个类必须显式声明为实现ICombatantGameObjectController,即使添加该声明也不需要添加任何额外的代码。如果这样做,可以毫无困难地使用ICombatantGameObjectController类型的参数,字段和变量。
如果你不能像上面所描述的那样设置你的类和接口,那么Jon Skeet提供的方法通常很好,但有一个令人讨厌的警告:调用像Skeet先生的ComputeAttackUpdate这样的通用函数,编译器已经能够确定它知道的单个类型与传入的对象的类型以及所有约束是否兼容。如果GameObjectController的后代实现了ICombatant但是没有从也实现GameObjectController的公共基类型派生,则可能难以将这些对象存储在字段中,然后将它们传递给泛型例程。有一种方法,如果你需要我可以解释它,但它有点棘手。