5

我需要你的帮助。我正在安排一个脚本,该脚本可以在角色扮演游戏中执行能力之前检查各种条件。

所有这些能力都在单独的类(火球、治疗、毒药)中,都派生自另一个抽象类(远程能力、治疗能力、DOT 能力),它们都是抽象类(能力)的父级。

为了避免创建多个功能,处理每一个能力:

void condition(Fireball f){//test}; 
void condition(Heal f){//test}; 
void condition(Poison f){//test};

我正在尝试创建一个可以采用所有类型能力的单个函数调用。

void condition(Ability f){//test}

到目前为止,我已经成功创建了一个 Fireball 对象并将其传递给函数。

Fireball _fire = new FireBall();
condition(_fire);

void condition(Ability f){//test}

从这里我可以访问在Ability 类中初始化的所有公共变量,但我无法访问在派生类中初始化的公共变量(Ranged 能力、Healing 能力、DOT 能力)。

是我忘记了什么,还是我看错了?(我不擅长利用继承和抽象类。)

4

1 回答 1

8

在不了解条件函数的更多细节的情况下,您有两个选择。

一,你可以做类似的事情

if (f.GetType() == typeof(FireBall))
{
  fireBall = (FireBall)f;
  fireBall.FireTheFireBall();
}
else if (f.GetType() == typeof(Heal))
...

或者,您的 Ability 可以有一个抽象的 Activate 方法,所有派生类都需要重载该方法:

class Fireball
{
   public override void Activate()
   {
       //do fireball specific things
       this.FireTheFireBall();
   }   

   public void FireTheFireBall() {...}    
}

class Heal
{
   public override void Activate()
   {
       //do healing specific things
       this.ApplyTheBandage();
   }
   ...
}

abstract class Ability
{
  public abstract void Activate();
}

void condition(Ability f){
   f.Activate(); //runs the version of Activate of the derived class
}

然后任何与能力一起工作的东西都可以调用 someAbility.Activate() 并且派生类提供的实现将被执行。

您还应该学习接口,它有点像抽象类。接口的好处是您可以实现多个接口,而您只能从一个基本抽象类继承。考虑一个具有转动和拉动功能的 IKnob 界面。您可能有一个实现 IKnob 的 Drawer 类、一个 Door 类、一个实现 Turn 并激活陷阱的 TrappedDoor 类。玩家走到一扇门前,按下门上的 Use 按钮​​,然后将对象 Open(IKnob 旋钮)传递给 open 函数

void Open(IKnob knob)
{
   knob.Turn();
   knob.Pull();
}

class TrappedDoor:IKnob,IMaterial,ISomethingElse,IHaveTheseOtherCapabilitiesAsWell
{
  private bool TrapAlreadySprung{get;set;}
  //more complex properties would allow traps to be attached either to the knob, or the door, such that in one case turning the knob activates the trap, and in the other, Pull activates the trap
  public Turn() { 
    if(! TrapAlreadySprung)
    {
      MessageBox("You hit your head, now you're dead");
    }
  }
}

有一些方法可以检查某物是否有接口,因此如果某个玩家走到一个物品前并尝试与它交谈,您可以检查该对象是否具有 ICanTalk 接口,如果有则调用 object.GetReply("Hello")并且对象可以响应。因此,如果您愿意,您可以拥有会说话的门和石头。您将获得处理与事物交谈/显示响应等的所有代码,使用 ICanTalk 接口方法,然后其他类可以实现 ICanTalk 并且它们各自决定如何响应被交谈。这个概念被称为“关注点分离”,可以帮助您创建更多可重用的代码。

重要的是你可以编写一段代码、一个算法、函数等,只适用于那个接口,这样一旦你让那个代码和接口一起工作,你就可以在任何类上使用那个接口,并且该类可以利用现有代码。

即你的condition函数,如果它接受了一个 IAbility 接口,一旦你的代码工作,那么你创建的任何实现 IAbility 的类都可以传递给条件函数。条件函数负责做它应该做的任何事情,实现 IAbility 的类负责它实现的方法中特定于它的任何事情。

当然,实现抽象类或接口的类必须实现所需的方法,所以有时您可能会觉得自己在复制代码。例如,如果您有类似的类,例如 TrappedDoor 和 Door,如果 TrappedDoor 未设置/已经弹出,则 TrappedDoor 的行为可能与常规 Door 一样。因此,在这种情况下,您可能要么继承自 Door,要么拥有私有 Door 属性(称为“组合”)。如果陷阱已经弹出,那么您可以调用基类 Door 或私有 Door 属性并调用 .Turn ,以便在陷阱未激活的情况下重用常规门的默认行为。

测试对象是否实现接口

就我个人而言,我主要使用接口和组合,而不是继承。并不是说继承很糟糕,而是继承层次结构很快就会变得非常复杂。

于 2013-01-10T22:44:18.830 回答