簡體   English   中英

重構通用的compareTo方法

[英]Refactoring generic compareTo method

我在做什么:

我有一個名為Os的容器類,它可以包含不同的類型元素以及類Os實例。 當我比較這堂課時,我想看看:

  • 淺等於元素
  • Os元素的深度相等

我已確保類中包含的每個元素:

  • 不能為null。
  • 與同類元素相當。
  • 是一成不變的。 好吧,至少我正在檢查一部分。

以下是我目前的情況。

例:

例如,此測試用例將通過。

    Os o1 = Os.of(3, 4d, Os.of("-"));
    Os o2 = Os.of(Os.of(Character.toString('-')), 4.0, new Integer(3));

    assertEquals(o1.toString(), "[3, 4.0, [-]]");
    assertEquals(o2.toString(), "[[-], 4.0, 3]");
    assertTrue(o1.reverse().compareTo(o2) == 0);

代碼示例:

compareTo方法:

@Override
public int compareTo(final Os that) {
    final int BEFORE = -1;
    final int EQUAL = 0;
    final int AFTER = 1;
    int subresult = 0;
    Comparable<?> othis;
    Comparable<?> othat;

    if (that == null)
        return AFTER;
    if (this == that)
        return EQUAL;

    subresult = ((Integer) this.o.size()).compareTo(that.o.size());
    if (subresult < 0)
        return BEFORE;
    else if (subresult > 0)
        return AFTER;

    try {
        for (int i = 0; i < this.o.size(); i++) {
            othis = this.o.get(i);
            othat = that.o.get(i);

            if (othis.getClass() == othat.getClass()) {
                if (othat instanceof Os) {
                    subresult = ((Os) othis).compareTo(((Os) othat));
                    if (subresult < 0)
                        return BEFORE;
                    else if (subresult > 0)
                        return AFTER;
                } else {
                    subresult = hackCMP(othis, othat);
                    if (subresult < 0)
                        return BEFORE;
                    else if (subresult > 0)
                        return AFTER;
                }
            } else {
                subresult = othis.getClass().getName()
                        .compareTo(othat.getClass().getName());
                if (subresult < 0)
                    return BEFORE;
                else if (subresult > 0)
                    return AFTER;
            }
        }
        return EQUAL;
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return BEFORE;
}

private static int hackCMP(Object val, Object val2)
        throws SecurityException, NoSuchMethodException,
        IllegalArgumentException, IllegalAccessException,
        InvocationTargetException {
    Method m = val.getClass().getMethod("compareTo", val.getClass());
    return (Integer) m.invoke(val, val2);
}

題:

我想重構代碼。

例如:

  • 如果可能,我寧願不使用hackCMP方法。
  • 以下代碼段似乎重復很多。 我可以用什么代替它嗎?

      subresult = <expression>; if (subresult < 0) return BEFORE; else if (subresult > 0) return AFTER; //else ... 

我可以重構什么,怎么做?

編輯:

@wolfcastle:數據存儲在private final ImmutableList<Comparable<?>> o;

我想提一下,每個答案都很有用。 以下似乎有效:

@Override
public int compareTo(final Os that) {
    Ordering<Iterable<Comparable<?>>> order = //
    Ordering.natural().<Comparable<?>> lexicographical();
    int result = -1;

    try {
        result = ComparisonChain.start()
                .compare(this.o.size(), that.o.size())
                .compare(this.o, that.o, order).result();
    } catch (Exception e) { //ignore: type mismatch
    }

    return result;
}

我會考慮的一種選擇是將元素存儲在一個類中,如果它們不是同一類,則允許按類而不是用compareTo方法比較它們:

private static class Element implements Comparable<Element> {
  // raw Comparable allows you to call compareTo
  private final Comparable comparable;

  Element(Comparable comparable) {
    this.comparable = comparable;
  }

  @Override @SuppressWarnings("unchecked")
  public int compareTo(Element o) {
    Comparable other = o.comparable;
    if(comparable.getClass().isInstance(other)) {
      return comparable.compareTo(other);
    }

    return comparable.getClass().getName().compareTo(other.getClass().getName());
  }

  @Override
  public boolean equals(Object obj) {
    return obj instanceof Element && comparable.equals(((Element) obj).comparable);
  }

  @Override
  public int hashCode() {
    return comparable.hashCode();
  }

  @Override
  public String toString() {
    return comparable.toString();
  }
}

然后,內部列表為List<Element> ,則OscompareTo方法可能非常簡單。 使用Guava ,可能非常簡單:

@Override
public int compareTo(Os o) {
  return ComparisonChain.start()
       .compare(list.size(), o.list.size())
       .compare(list, o.list, Ordering.natural().<Element>lexicographical())
       .result();
}

您可能有一個返回BEFORE |的方法。 之后| INDETERMINATE(說),然后調用它。

result = newMethod(subresult);
if (result != INDETERMINATE) return result;

這並不是什么很大的改進,它仍然需要在所有地方重復,但是要更緊密一些。

由於List<Comparable<?>> o屬性的泛型類型是不固定的,因此我將擺脫泛型類型並依賴原始類型。 它花費了一個@SuppressWarnings("rawtypes") ,但是將其最小化了。

@Override
@SuppressWarnings("rawtypes")
public int compareTo(final Os that) {
    final int BEFORE = -1;
    final int EQUAL = 0;
    final int AFTER = 1;

    if (that == null)
        return AFTER;
    if (this == that)
        return EQUAL;

    int subresult = ((Integer) this.o.size()).compareTo(that.o.size());

    if (subresult != EQUAL)
        return subresult;

    for (int i = 0; i < this.o.size(); i++) {
        Comparable othis = this.o.get(i);
        Comparable othat = that.o.get(i);
        subresult = othis.compareTo(othat);

        if (subresult != EQUAL)
            return subresult;
    }

    return EQUAL;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM