黑社会不露面战斗吗? (Java Set缺少项目)
作者:互联网
我有两家公司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);
}
asoft提供了GangWar,使IGangs可以战斗:
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!");
}
}
}
它需要附加的约束条件,即您提供给它的帮派是可比较的,大概是它可以按名称排序或避免重复.每个帮派(为简单起见,这里使用任意顺序的Set顺序)都会攻击另一个帮派,直到只剩下一个帮派(或者如果最后两个有平局,就没有帮派).我编写了一个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!
问题是,三合会不会出现在战斗中.实际上,在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?
三合会和格罗夫街的强度均为9.因此,它们在Gang.compareTo(实现Comparable)方面相等.因此,TreeSet中仅允许一个.
如果您不想删除按排序顺序重复的项目,请不要使用TreeSet …
编辑:ComparableGang接口说明指出了所期望的:
/** An `IGang` ordered by identity (name) */
public interface ComparableGang extends IGang, Comparable<IGang> {}
您的compareTo方法不按“标识(名称)”排序-而是按强度排序.老实说,这首先是一个非常愚蠢的接口,因为对于asoft来说,创建一个公共类GangNameComparator:Comparator< IGang>然后将其作为树集的比较器是非常容易的想按名称订购.
但是,由于他们建议您实施比较,因此您需要按照界面说明进行操作:
public int compareTo(IGang g) {
return name.compareTo(g.getName());
}
但是,正如您在评论中(以及Rob的回答中所指出的那样),这与约定俗称的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实现,仅了解IGang,并依赖IGang合同之后的实现.但是,asoft通过在扩展IGang的接口中要求不同的行为打破了这一假设.
只要他们不违反IGang的现有要求,他们在ComparableGang中添加更多要求是合理的.
请注意,这是C#和Java之间的重要区别.在C#中,两个具有相同签名的不同接口中的两个函数可以组合为一个继承了它们和the two methods remain distinct and accessible的接口.在Java中,这两种方法是完全抽象的,并且具有相同的签名,因此它们是considered to be the same method和a实现组合接口的类只有一种这样的方法.因此,在Java中,ComparableGang是无效的,因为它不能具有满足ComparableGang合同和IGang合同的compareTo()实现.
标签:diamond-problem,java,interface,set 来源: https://codeday.me/bug/20191011/1891839.html