三合会没有出现在战斗中? (Java设置缺少一个项目) [英] Triads not showing up to fight? (Java Set missing an item)

查看:144
本文介绍了三合会没有出现在战斗中? (Java设置缺少一个项目)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have code from two companies asoft and bsoft. I cannot change either. This is a simplified version of my situation which I'm pretty sure has enough information to the find what's causing the problem.

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

bsoft provides IGang, which represents a gang that can battle other gangs.

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);
}

asoft提供 GangWar ,允许 IGang s进行战斗:

asoft provides GangWar, which allows IGangs to battle:

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 的实现来测试它:

It requires the additional constraint that the Gangs you supply to it are Comparable, presumably so it can sort by name or avoid duplicates. Each gang (in an arbitrary order, Set order used here for simplicity) attacks another gang, until only one gang is left (or no gangs, if the last two have a tie). I've written a simple implementation of ComparableGang to test it out:

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();
   }
}

测试出来......

Testing it out...

$ 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!

问题是,三合会没有出现在战斗中。实际上,在 doBattle()的开头打印 gangs.size()会返回3而不是4.为什么?如何解决?

The problem is, triads do not show up to the fight. In fact, printing gangs.size() right at the start of doBattle() returns 3 instead of 4. Why? How to fix it?

推荐答案


问题是,三合会没有出现在战斗中。实际上,在doBattle()开头打印gangs.size()会返回3而不是4.为什么?

The problem is, triads do not show up to the fight. In fact, printing gangs.size() right at the start of doBattle() returns 3 instead of 4. Why?

两者三元组 grove street 的强度为9.因此它们在 Gang方面是相同的.compareTo (实现 Comparable )。因此, TreeSet 中只允许一个。

Both triads and grove street have a strength of 9. Therefore they're equal in terms of Gang.compareTo (implementing Comparable). Therefore only one is permitted in a TreeSet.

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

If you don't want to remove items which are duplicates in terms of their sort order, don't use a TreeSet...

编辑: ComparableGang 界面描述表明预期:

The ComparableGang interface description indicates what's expected:

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

您的 compareTo 方法订单按身份(名称) - 按强度排序。说实话,它首先是一个非常愚蠢的界面,因为 asoft 非常容易创建一个类的公共类GangNameComparator :比较器< IGang> ,然后将它作为比较器提供给树集,如果他们想按名称排序。

Your compareTo method does not order "by identity (name)" - it orders by strength. To be honest, it's a pretty stupid interface in the first place, as it would have been perfectly easy for asoft to create a class of public class GangNameComparator : Comparator<IGang>, and then supply that as the comparator to the tree set if they wanted to order by name.

但是,as他们建议你应该实现比较,你需要这样做,因为界面描述:

However, as they're suggesting that you should implement the comparison, you need to do so as the interface describes:

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

但是......正如你在评论中所说的那样(并且如Rob的回答中所述) ),这与大会命名的 IGang 描述相矛盾:

However... as you note in comments (and as noted in Rob's answer), this then contradicts the convention-bustingly-named IGang description:

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的部分,这基本上被设计破坏了。

It's impossible to implement ComparableGang to satisfy both its own documentation and the IGang documentation. This is basically broken by design, on asoft's part.

任何代码都应该能够使用 IGang 实现,知道关于 IGang ,并依赖于 IGang 合同之后的实施。然而,asoft通过在扩展 IGang 的接口中要求不同的行为来打破这种假设。

Any code should be able to use an IGang implementation, knowing only about IGang, and relying on the implementation following the IGang contract. However, asoft broke that assumption by requiring different behaviour in an interface extending IGang.

这是合理的他们在 ComparableGang 中添加更多要求,只要它们没有违反<$ c> 现有的要求$ c> IGang 。

It would have been reasonable for them to add more requirements in ComparableGang, so long as they didn't violate the existing requirements of IGang.

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

Note that this is an important difference between C# and Java. In C#, two functions in two different interfaces with the same signature can be combined into one interface that inherits both of them and the two methods remain distinct and accessible. In Java, the two methods, since they are completely abstract and have the same signature, are considered to be the same method and a class implementing the combined interfaces has only one such method. So in Java ComparableGang is invalid because it cannot have an implementation of compareTo() that satisfies the contract of ComparableGang and the contract of IGang.

这篇关于三合会没有出现在战斗中? (Java设置缺少一个项目)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆