java – 实现接口比较器

前端之家收集整理的这篇文章主要介绍了java – 实现接口比较器前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
假设我有一个简单的界面,我希望基于某些功能可比较:
  1. interface Organism extends Comparable<Organism> {
  2. String getName();
  3. int getComplexity();
  4.  
  5. @Override
  6. default int compareTo(Organism other) {
  7. return this.getComplexity() - other.getComplexity();
  8. }
  9. }

每个实现类必须返回唯一的复杂性,因此类的任何两个实例将具有相同的复杂性,并且不同类的任何两个实例将具有不同的复杂性.自然排序将所有类的实例“组合”在一起.

我现在想要在一个类中实现此接口,该类重写默认比较,专门用于比较该类的实例组中该类的两个实例.我使用以下模式:

  1. class Bacteria implements Organism {
  2. enum Shape {ROD,ROUND,SPIRAL};
  3. private final Shape shape;
  4.  
  5. @Override
  6. public int compareTo(Organism other) {
  7. if (other instanceof Bacteria)
  8. return this.shape.compareTo((Bacteria)other.shape);
  9. else
  10. return Organism.super.compareTo(other);
  11. }
  12. }

我对这种代码模式并不是特别满意:一旦实现接口的类集变得很大,维护变得非常复杂并且需要大量重复的代码并依赖于“复杂性”的隐含属性.我更喜欢定义订单的比较器风格.我希望能够使用看起来像这样的东西来实现细菌中的Comparable:

  1. return Comparator
  2. .comparingInt(Organism::getComplexity)
  3. .thenComparing(Bacteria::getShape);

为了清楚起见,我意识到比较器不能像这样工作:它们被设计成在一个集合中使用一个比较器,而不是根据每个对象使用不同的比较器.我在这里提到它们并不是因为它们是一种潜在的解决方案,而是因为比较器的链式风格优雅而透明.我感兴趣的是,是否有一种同样优雅的方式来定义compareTo以允许集合中的不同排序取决于类.

解决方法

我不确定你打算把比较器放在哪里.既然你希望你的班级实现Comparable< Organism>,我会假设你正在寻找像
  1. class Bacteria implements Organism {
  2. enum Shape {ROD,SPIRAL};
  3. private final Shape shape;
  4.  
  5. Comparator<Organism> comparator =
  6. Comparator
  7. .comparingInt(Organism::getComplexity)
  8. .thenComparing(Bacteria::shape); // illegal
  9.  
  10. @Override
  11. public int compareTo(Organism other) {
  12. return comparator.compare(this,other);
  13. }
  14. }

这不起作用,因为在上下文中,比较需要一个参数,该参数是一个在生物上运行的函数,而不是一个细菌.你可以像这样解决它 – 我会留给你判断这是否足够优雅:

  1. Comparator<Organism> comparator =
  2. Comparator
  3. .comparingInt(Organism::getComplexity)
  4. .thenComparing(x -> ((x instanceof Bacteria) ? ((Bacteria)x).getShape() : Shape.ROD));

理论上,您也可以编写自己的方法,将比较器转换为另一个.你不能使用instance.method表示法,所以使用必须是这样的:

  1. Comparator<Organism> comparator =
  2. MyComparatorUtilities.thenComparingIfInstanceOf(
  3. Comparator.comparingInt(Organism::getComplexity),Bacteria.class,Bacteria::getShape);

thenComparingIfInstanceOf的以下实现编译(并允许上面的代码编译),但我还没有尝试测试它:

  1. class MyComparatorUtilities {
  2. public static
  3. <T,U extends T,V extends Comparable<? super V>> Comparator<T> thenComparingIfInstanceOf(
  4. Comparator<T> comparator,Class<U> subclass,Function<? super U,? extends V> keyExtractor) {
  5. return (a,b) -> {
  6. int comp = comparator.compare(a,b);
  7. if (comp != 0) {
  8. return comp;
  9. }
  10. if (subclass.isInstance(a) && subclass.isInstance(b)) {
  11. return keyExtractor.apply(subclass.cast(a))
  12. .compareTo(keyExtractor.apply(subclass.cast(b)));
  13. }
  14. return 0;
  15. };
  16. }
  17. }

更多:回答评论:不,我不一定认为这种方法更具可读性或可维护性.事实上,我认为整个设计是不可维护的,因为添加一个会导致比较违反总排序属性的类太容易了;我正在寻找一种不同的设计,从更明确的定义开始,我希望订单如何处理不同类的对象.处理比较的“正确”方式可能取决于不同的设计.

对于类似的问题,我可能会坚持使用compareTo方法,除非我因为某些其他原因需要一个类来返回Comparator(例如,为Organisms定义了多个排序).但是,如果每个compareTo都是具有相同结构的if语句,或者类似的东西,我可能会寻找消除重复的方法.

猜你在找的Java相关文章