Как реализовать CompareTo для всех реализаций интерфейса? - PullRequest
2 голосов
/ 18 апреля 2019

В 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 ]

2 голосов
/ 18 апреля 2019

Вы можете переместить это приведение 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 голос
/ 25 апреля 2019

Итак, это лучшее, что я когда-либо придумал, который смешивает мой оригинальный подход с ответом Руслана и пытается управлять компромиссами:

Определяем интерфейс без рекурсивных обобщений:

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());
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...