【问题标题】:Split off logic in methods when custom Comparator is provided or elements implements Comparable?提供自定义 Comparator 或元素实现 Comparable 时在方法中拆分逻辑?
【发布时间】:2015-02-13 10:31:16
【问题描述】:

在方法中拆分逻辑的最佳实践是什么,谁将使用 Comparable 元素,或者在创建时提供特定的 Comparator,具体取决于使用的类的构造函数? 示例:

public class MinMax<E> {

private final Comparator<? super E> comparator;
private final boolean isSpecificComparatorProvided;

public MinMax() {
    this.comparator = null;
    this.isSpecificComparatorProvided = false;
    ........;
}

public MinMax(Comparator<? super E> comparator) {
    this.comparator = comparator;
    this.isSpecificComparatorProvided = true;
    ........;
}

private boolean isBigOrEqual(E e1, E e2) {
    if (isSpecificComparatorProvided) {
        Comparator<? super E> cpr = comparator;
        int cmpr = cpr.compare(e1, e2);
        return cmpr > -1;
    } else {
        @SuppressWarnings("unchecked")
        Comparable<? super E> e1Comparable = (Comparable<? super E>) e1;
        int cmprTo = e1Comparable.compareTo(e2);
        return cmprTo > -1;
    }
}

}

我是否总是检查方法 isBigOrEqual() 中的特定比较器? 当没有提供特定的 Comparator 时,是否还需要对 Comparable 进行强制转换? 还有其他方法吗?

【问题讨论】:

    标签: java collections comparator comparable


    【解决方案1】:

    可能最简单的处理方法是只实现Comparator 的情况,然后当你没有通过Comparator 时,编写一个只适用于Comparable 的情况。 (在 Java 8 中,这只是 Comparator.naturalOrder()。)

    new Comparator<T> {
      @Override public int compare(T a, T b) {
        return a.compareTo(b);
      }
    };
    

    TreeMap 出于性能原因不这样做,但这样做更简单。

    【讨论】:

      【解决方案2】:

      您可以将E 限制为与public class MinMax&lt;E extends Comparable&lt;E&gt;&gt; 相似,因此不再需要强制转换,因为E 必须在编译时具有可比性:

      public class MinMax<E extends Comparable<E>> {
      
          private final Comparator<? super E> comparator;
      
          private final boolean isSpecificComparatorProvided;
      
          public MinMax() {
              this.comparator = null;
              this.isSpecificComparatorProvided = false;
          }
      
          public MinMax(Comparator<? super E> comparator) {
              this.comparator = comparator;
              this.isSpecificComparatorProvided = true;
          }
      
          private boolean isBigOrEqual(E e1, E e2) {
              if (this.isSpecificComparatorProvided) {
                  return this.comparator.compare(e1, e2) > -1;
              } else {
                  return e1.compareTo(e2) > -1;
              }
          }
      }
      

      【讨论】:

      • 这个答案对我来说似乎很有用。我想问一下,据我了解,如果 E 没有实现 Comparable ,但提供了特定的 Comparator ,在运行时不会有问题,对吧?
      • 没有。如果 E 没有实现 Comparable 会出现编译错误。
      • 如果您不确定E 是否会实现Comparable,即使您的代码也会失败,因为您转换为Comparable
      【解决方案3】:

      在我看来,您想抽象出一种比较 E 类型的两个对象的方法,并且有两种实现。一个使用特定的Comparator,而另一个处理Comparable 对象。因此,您可以将这两种行为拆分为单独的类(实现)。

      让我们从抽象概念的接口开始:

      interface AbstractComparer<E> {
          public boolean isBigOrEqual(E e1, E e2);
      }
      

      对不起,这个没有灵感的名字。

      接下来,我们来实现处理 Comparable 对象的案例:

      class ComparableComparer<E extends Comparable<E>> implements AbstractComparer<E> {
      
          @Override
          public boolean isBigOrEqual(E e1, E e2) {
              return e1.compareTo(e2) > -1;
          }
      
      }
      

      另一种情况的实现通过构造函数接收特定的比较器:

      class ComparatorComparer<E> implements AbstractComparer<E> {
      
          private Comparator<E> comparator;
      
          public ComparatorComparer(Comparator<E> comparator) {
              this.comparator = comparator;
          }
      
          @Override
          public boolean isBigOrEqual(E e1, E e2) {
              return this.comparator.compare(e1, e2) > -1;
          }
      }
      

      现在,我们可以简化MinMax 类,我们可以通过构造函数提供比较方法:

      public class MinMax<E> {
      
          private final AbstractComparer<E> comparer;
      
          public MinMax(AbstractComparer<E> comparer) {
              this.comparer = comparer;
          }
      
          private boolean isBigOrEqual(E e1, E e2) {
              return comparer.isBigOrEqual(e1, e2);
          }
      }
      

      【讨论】:

      • 非常好的解决方案。我认为我会找到从 java 集合框架中查看知名类的源代码的最佳实践,例如 TreeMap ,但由于代码量大,我无法弄清楚。对于 TreeMap 中的键 K ,情况就像在我的情况下一样,两个构造函数 - 一个用于使用键的自然顺序,并且所有插入映射的键都必须实现 Comparable 接口。提供 Comparator 时的第二个构造函数。
      • 哪种方法更好值得商榷。使用我的方法,它更清晰、更安全,因为您避免使用没有指定Comparator 的非Comparable 对象。而且您不必到处使用comparator == null 检查代码。但是如果 TreeMap 是按照我的方式实现的,那么 TreeMap 的用户将不得不总是提供一个 AbstractComparer 对象,这会很烦人。因此,您必须决定哪种方法更适合您的需求。
      猜你喜欢
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 2015-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 2014-07-05
      • 1970-01-01
      相关资源
      最近更新 更多