如何为接口的所有实现实现compareTo?

时间:2019-04-18 15:49:50

标签: java generics interface compareto

在Java中,为接口的所有实现提供自然顺序的最佳方法是什么?

我有一个接口,我想通过扩展Comparable接口来确保/提供所有实现之间的自然顺序:

public interface MyInterface extends Comparable<MyInterface> {

}

此接口将有几种实现,每种实现都可以为其自己的实例定义自然排序,但是可能不知道如何针对其他实现来进行排序。

我使用的一种方法是引入递归泛型,并按实现和实例划分自然顺序比较:

public interface MyInterface<X extends MyInterface<X>> extends Comparable<MyInterface> {

  @Override
  default int compareTo(MyInterface o) {
    // the interface defines how to compare between implementations, say...
    int comp = this.getClass().getSimpleName().compareTo(o.getClass().getSimpleName());
    if (comp == 0) {
      // but delegates to compare between instances of the same implementation
      comp = compare((X) o);
    }
    return comp;
  }

  int compare(X other);
}

这意味着MyInterface的实现只需在自己的实例之间进行比较:

public class MyClass implements MyInterface<MyClass> {

  public int compare(MyClass other) {
    return 0; // ... or something more useful... 
  }
}

但是,递归泛型可能变得很难维护。

有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

您可以将此强制转换compare((X) o);从接口的默认方法移至实现,因此根本不需要通用<X extends MyInterface<X>>

public interface MyInterface extends Comparable<MyInterface> {
    @Override
    default int compareTo(MyInterface o) {
        ...
        comp = compare(o);
        ...
    }
    int compare(MyInterface other);
}

在这种情况下,实现可能如下所示:

public class MyClass implements MyInterface {
    private Integer property;
    public int compare(MyInterface other) {
        return Integer.compare(this.property, ((MyClass) other).property);
    }
}

答案 1 :(得分:1)

因此,这是到目前为止我能想到的最好的方法,它将我的原始方法与Ruslan's answer融合在一起,并试图权衡取舍:

我们定义了没有递归泛型的接口:

public interface MyInterface extends Comparable<MyInterface> {

  @Override // as per the Comparable interface (not needed, but included here for clarity)
  int compareTo(MyInterface o);
}

然后,我们创建一个抽象类,该抽象类定义实现之间的比较,并委托给实现以在该实现的实例之间进行比较。由于我们将compare()方法的范围限制为protected,因此在接口中具有此功能得到了改善。

public abstract class MyAbstractClass implements MyInterface {

  @Override
  public int compareTo(MyInterface o) {
    // the interface defines how to compare between implementations, say...
    int comp = this.getClass().getSimpleName().compareTo(o.getClass().getSimpleName());
    if (comp == 0) {
      // but delegates to compare between instances of the same implementation
      comp = compare(o);
    }
    return comp;
  }

  protected abstract int compare(MyInterface other);
}

然后在每个实现中,我们检查/投射到该实现。绝对不要使用其他实现来调用它,但是为了安全起见,如果发生这种情况,我们将抛出IllegalArgumentException

public class MyClass implements MyInterface {

  public int compare(MyClass o) {
    if (o instanceof MyClass) {
      return 0; // ... or something more useful... 
    } else {
      throw new IllegalArgumentException("Cannot compare " + this.getClass() + " with " + o.getClass());
    }
  }
}