使用继承和多态性解决常见的博弈问题

2022-09-02 00:46:12

我有两个班级;让我们称它们为食人魔和巫师。(所有字段都是公共的,以使示例更易于输入。

public class Ogre
{
  int weight;
  int height;
  int axeLength;
}

public class Wizard
{
  int age;
  int IQ;
  int height;
}

在每个类中,我都可以创建一个名为battle()的方法,该方法将决定如果食人魔遇到食人魔或巫师遇到巫师,谁将获胜。下面是一个示例。如果食人魔遇到食人魔,那么体重较重的食人魔获胜。但是,如果重量相同,则斧头较长的那个获胜。

public Ogre battle(Ogre o)
{
  if (this.height > o.height) return this;
  else if (this.height < o.height) return o;
  else if (this.axeLength > o.axeLength) return this;
  else if (this.axeLength < o.axeLength) return o;
  else return this;    // default case
}

我们可以为巫师制作类似的方法。

但是,如果巫师遇到食人魔呢?我们当然可以为此制定一种方法,比较,比如说,只是高度。

public Wizard battle(Ogre o)
{
  if (this.height > o.height) return this;
  else if (this.height < o.height) return o;
  else return this;
}

我们会为食人魔做一个类似的,遇到巫师。但是,如果我们必须向程序添加更多字符类型,事情就会失控。

这就是我陷入困境的地方。一个明显的解决方案是创建一个具有共同特征的 Character 类。食人魔和巫师从角色那里继承并扩展它以包括定义每个角色的其他特征。

public class Character
{
  int height;

  public Character battle(Character c)
  {
    if (this.height > c.height) return this;
    else if (this.height < c.height) return c;
    else return this;
  }
}

有没有更好的方法来组织课程?我已经研究了策略模式和调解员模式,但我不确定它们中的任何一个(如果有的话)如何在这里提供帮助。我的目标是达到某种常见的战斗方法,这样,如果食人魔遇到食人魔,它就会使用食人魔与食人魔的战斗,但是如果食人魔遇到巫师,它就会使用更通用的巫师。此外,如果相遇的角色没有共同的特征怎么办?我们如何决定谁能赢得一场战斗?

编辑:很多很棒的回应!我需要消化它们,并找出哪一个最适合我的情况。


答案 1

访问者模式“是一种将算法与其操作的对象结构分开的方法”。

对于您的示例,您可以

class Character {
    boolean battle(BattleVisitor visitor) {
       return visitor.visit(this);
    }
}

class Ogre extends Character {..}
class Wizard extends Character {..}
class Dwarf extends Character {..}

interface BattleVisitor {
    boolean visit(Ogre character);
    boolean visit(Wizard character);
    boolean visit(Dwarf character);
}

class OgreBattleVisitor implements BattleVisitor {
    private Ogre ogre;
    OgreBattleVisitor(Ogre ogre) { this.ogre = ogre; }
    boolean visit(Ogre ogre) {
      // define the battle 
    }

    boolean visit(Wizard wizard) {
      // define the battle 
    }
    ...
}

每当发生争吵时:

targetChar.battle(new OgreBattleVisitor(ogre));

为向导和矮人以及出现的任何内容定义访客实现。另请注意,我将方法的结果定义为(赢或输)而不是返回赢家。visitboolean

因此,在添加新类型时,必须添加:

  • 一种方法,让访问者处理战斗新类型。
  • 用于处理新类型战斗的实现

现在,事实证明,在“食人魔vs巫师”==“巫师与食人魔”的情况下,您将有一些重复的代码。我不知道情况是否如此 - 例如,根据谁先罢工,可能会有区别。另外,您可能希望提供完全不同的算法,例如“与食人魔的沼泽战斗”与“与食人魔的村庄战斗”。因此,您可以创建一个新的访问者(或访问者层次结构),并在需要时应用适当的访问者。


答案 2

如果两只食人魔具有相同的身高/体重相同的斧头长度,会发生什么?根据你的例子,有幸首先被召唤的人会赢。

我不知道这是否是一个合适的选择,但是如果你采用一个完全不同的方案,为每个角色分配一个“战斗分数”,而不是依靠比较个人特征,那会怎么样?您可以在公式中使用字符的属性来给出一些可以与另一个字符进行比较的整数。然后,您可以使用通用方法来比较两个分数,并将字符与较高的分数返回。battle

例如,如果食人魔的“战斗得分”是按他的身高加上他的体重乘以斧头长度来计算的,而巫师的得分是用他的年龄乘以他的智商来计算的呢?

abstract class Character {
    public abstract int battleScore();

    public Character battle(Character c1, Character c2) {
        (c1.battleScore() > c2.battleScore()) ? return c1 : c2;
    }
}

class Ogre extends Character {
    public int battleScore() {
        return (height + weight) * axeLength;
    }
 }

 class Wizard extends Character {
    public int battleScore() {
        return height + (age * IQ);
    }
 }