.Net中的接口继承/层次结构 - 有更好的方法吗?

Ter*_*al8 6 c# inheritance interface

我想我会在我的代码中使用一些案例研究作为我的意思的一个例子.

现在,我正在为基于组件的游戏系统开发一个行为/动作系统.GameObjects可以附加一个IBehaviorComponent和一个IActionComponent,只显示相关细节,公开以下内容:

public interface IBehaviorComponent : IBaseComponent
{
   IBehavior Behavior { get; }
}

public interface IActionComponent : IBaseComponent
{
   IAction Action { get; }
   void ExecuteAction(IGameObject target = null);
}
Run Code Online (Sandbox Code Playgroud)

现在,到目前为止这一切都很好(至少对我而言!).但是,当我查看IActionComponent的实现时,麻烦开始酿造.

例如,一个简单的IActionComponent实现:

public class SimpleActionComponent : IActionComponent
{
   public IAction Action { get; protected set; }

   public void ExecuteAction(IGameObject target = null)
   {
      Action.Execute(target);
   }

   public void Update(float deltaTime) { } //from IBaseComponent
}
Run Code Online (Sandbox Code Playgroud)

但是,假设我想引入一个更复杂的IActionComponent实现,它允许在定时计划上执行操作:

public class TimedActionComponent : IActionComponent
{
   public IAction Action { get; protected set; }

   public float IdleTime { get; set; }

   public float IdleTimeRemaining { get; protected set; }

   public void ExecuteAction(IGameObject target = null)
   {
      IdleTimeRemaining = IdleTime;
   }

   public void Update(float deltaTime)
   {
      if (IdleTimeRemaining > 0f)
      {
         IdleTimeRemaining -= deltaTime;
      }
      else
      {
         Action.Execute(target);
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

而现在,假设我想公开IdleTime,以便可以通过外部影响来改变它.我最初的想法是创建一个新界面:

public interface ITimedActionComponent : IActionComponent
{
   float IdleTime { get; set; }

   float IdleTimeRemaining { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

但是,这里的问题是我的组件系统将所有内容存储在IBaseComponent的一级.因此,GameObject的动作组件将被检索为IActionComponent,例如,ITimedActionComponent,或IRandomizedActionComponent,甚至是ICrashTheProgramActionComponent.我希望其中的原因是显而易见的,因为我希望能够查询GameObject中的一个组件,而不必知道除了组件的基本类型(IActionComponent,IRenderableComponent,IPhysicsComponent等)之外它究竟需要什么.

有没有更清晰的方法来处理这个,这将允许我公开子类中定义的这些属性,而不必将检索到的IActionComponent转换为它感兴趣的类型?或者这只是实现这一目标的唯一/最佳方式.就像是:

public void IWantYouToAttackSuperSlow(IGameObject target)
{
   //Let's get the action component for the gameobject and test if it's an ITimedActionComponent...
   ITimedActionComponent actionComponent = target.GetComponent<IActionComponent>() as ITimedActionComponent;

   if (actionComponent != null) //We're okay!
   {
      actionComponent.IdleTime = int.MaxValue; //Mwhaha
   }
}
Run Code Online (Sandbox Code Playgroud)

现在我认为这是唯一的方式,但我想我会看到是否有一种模式隐藏在我不知道的木制品中,或者是否有人可以建议一种更好的方法来实现这一点.

谢谢!

And*_*ren 0

你是对的,通过转换为子类型来测试特定的实现并不是一个好主意。从您提供的示例来看,您似乎想要对其IGameObject执行某些操作。与其IActionComponent公开一个以 为参数的方法,不如IGameObject以相反的方式进行操作,即让 采取IGameObject一个或多个(如果您愿意)可以执行的操作。

interface IActionComponent
{
    ExecuteAction();
}

interface IGameObject
{
    IActionComponent ActionComponent { get; }
}
Run Code Online (Sandbox Code Playgroud)

然后在执行方法中做

public void IWantYouToAttackSuperSlow(IGameObject target)
{
    target.ActionComponent.ExecuteAction();
}
Run Code Online (Sandbox Code Playgroud)

根据您实现 IActionComponent 的方式,多态性将确保执行正确的代码。

有一种称为命令模式的模式似乎适合您的需要。