三合会不出现战斗? (Java Set 缺少一项)

2023-12-05

我有来自两家公司 asoft 和 bsoft 的代码。我也无法改变。这是我的情况的简化版本,我确信有足够的信息来查找导致问题的原因。

bsoft提供IGang,代表一个可以与其他帮派作战的帮派。

package bsoft;

public interface IGang {
    /** @return negative, 0, or positive, respectively
     *          if this gang is weaker than, equal to, or stronger
     *          than the other
     */
    public int compareTo(IGang g);
    public int getStrength();
    public String getName();
    public void attack(IGang g);
    public void weaken(int amount);
}

阿软提供GangWar, 这使得IGang战斗:

package asoft;
import java.util.*;
import bsoft.*;
/** An `IGang` ordered by identity (name) */
public interface ComparableGang extends IGang, Comparable<IGang> {}

package asoft;
import java.util.*;

public class GangWar {
    public final Set<ComparableGang> gangs = new TreeSet<ComparableGang>();
    public void add(ComparableGang g) {gangs.add(g);}
    public void doBattle() {
        while (gangs.size() > 1) {
          Iterator<ComparableGang> i = gangs.iterator();
          ComparableGang g1 = i.next();
          ComparableGang g2 = i.next();
          System.out.println(g1.getName() + " attacks " + g2.getName());
          g1.attack(g2);
          if (g2.getStrength() == 0) {
              System.out.println(g1.getName() + " smokes " + g2.getName());
              gangs.remove(g2);
          }
          if (g1.getStrength() == 0) {
              System.out.println(g2.getName() + " repels " + g1.getName());
              gangs.remove(g1);
          }
        }
        for (ComparableGang g : gangs) {
            System.out.println(g.getName() + " now controls the turf!");
        }
    }
}

它需要额外的约束Gang你提供给它的是Comparable,大概这样它可以按名称排序或避免重复。每个帮派(以任意顺序,为简单起见,此处使用设定顺序)攻击另一个帮派,直到只剩下一个帮派(或者没有帮派,如果最后两个帮派平局)。我写了一个简单的实现ComparableGang测试一下:

import asoft.*;
import bsoft.*;
import java.util.*;

class Gang implements ComparableGang {
    final String name;
    int strength;

    public Gang(String name, int strength) {
        this.name = name;
        this.strength = strength;
    }

    public String getName() {return name;}
    public int getStrength() {return strength;}

    public int compareTo(IGang g) {
        return strength - g.getStrength();
    }

    public void weaken(int amount) {
        if (strength < amount) strength = 0;
        else strength -= amount;
    }

    public void attack(IGang g) {
        int tmp = strength;
        weaken(g.getStrength());
        g.weaken(tmp);

    }

    public boolean equals(Object o) {
      if (!(o instanceof IGang)) return false;
      return name.equals(((IGang)o).getName());
    }
}

class Main {
   public static void main(String[] args) {
       GangWar gw = new GangWar();
       gw.add(new Gang("ballas", 2));
       gw.add(new Gang("grove street", 9));
       gw.add(new Gang("los santos", 8));
       gw.add(new Gang("triads", 9));
       gw.doBattle();
   }
}

测试一下...

$ java Main
ballas attacks los santos
los santos repels ballas
los santos attacks grove street
grove street repels los santos
grove street now controls the turf!

问题是,黑社会不会出现在战斗中。事实上,印刷gangs.size()就在开始时doBattle()返回 3 而不是 4。为什么?如何修复它?


问题是,黑社会不会出现在战斗中。事实上,在 doBattle() 开始时打印 gangs.size() 返回 3 而不是 4。为什么?

Both triads and grove street强度为 9。因此它们在以下方面相等Gang.compareTo(实施Comparable)。因此,一个中只允许有一个TreeSet.

如果您不想删除排序顺序重复的项目,请不要使用TreeSet...

编辑:ComparableGang接口描述表明了预期的内容:

/** An `IGang` ordered by identity (name) */
public interface ComparableGang extends IGang, Comparable<IGang> {}

Your compareTo方法确实not“按身份(姓名)”排序 - 按实力排序。老实说,它首先是一个非常愚蠢的界面,因为它对于asoft创建一个类public class GangNameComparator : Comparator<IGang>,然后如果他们想按名称排序,则将其作为树集的比较器提供。

但是,由于他们建议您应该实现比较,因此您需要按照界面描述进行操作:

public int compareTo(IGang g) {
    return name.compareTo(g.getName());
}

然而......正如您在评论中指出的那样(以及罗布的回答中指出的那样),这与打破惯例的命名相矛盾IGang描述:

public interface IGang {
    /** @return negative, 0, or positive, respectively
     *          if this gang is weaker than, equal to, or stronger
     *          than the other
     */
    public int compareTo(IGang g);
}

是不可能实现的ComparableGang以满足其自己的文档和IGang文档。这基本上是由 asoft 的设计所打破的。

任何代码都应该能够使用IGang执行、了解only about IGang,并依赖于以下实施IGang合同。然而,asoft 打破了这一假设,要求接口中的不同行为扩展IGang.

他们添加的话是合理的更多要求 in ComparableGang,只要他们不违反existing的要求IGang.

请注意,这是 C# 和 Java 之间的一个重要区别。在 C# 中,具有相同签名的两个不同接口中的两个函数可以组合成一个继承它们的接口,并且这两种方法仍然不同且易于使用。在Java中,这两个方法是完全抽象的并且具有相同的签名,因此它们是被认为是 同样的方法并且实现组合接口的类只有一个这样的方法。所以in Java ComparableGang无效,因为它无法实现满足 ComparableGang 契约和 IGang 契约的compareTo() 实现。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

三合会不出现战斗? (Java Set 缺少一项) 的相关文章

随机推荐