2012-05-23 2 views
2

Мое приложение может сравнивать экземпляры любых двух подклассов одного и того же абстрактного родительского класса. Я хочу, чтобы они сравнивались следующим образом:Сравнение Java-подклассов

  1. Если они представляют собой разные подклассы, родительский класс должен выполнить сравнение.
  2. Если они являются одним и тем же подклассом, подкласс должен выполнить сравнение.

Классы будут сравниваться с TreeMap, поэтому у меня есть выбор использования компаратора или реализация Comparable (или обоих?).

Я могу придумать несколько способов сделать это, но все они немного грязны и подвержены ошибкам. Есть ли элегантное решение?

Заранее спасибо ...

+3

Что вы подразумеваете под «классами будет сравниваться с Treemap»? –

+0

Поскольку вы упоминаете Comparable и Comparator, можем ли мы предположить, что результат сравнения имеет все три возможности - «меньше», «больше» и «равно»? Если сравнение исключает возможность даже одного из этих параметров, то вы не должны использовать эти интерфейсы. –

+0

Вы хотите сравнить классы с помощью рефлексии? Как и в каких методах и свойствах каждый класс имеет? – user845279

ответ

2

Вы могли бы попробовать

// Parent: 
@Override 
public final int compareTo(Parent other) 
{ 
    if (getClass() == other.getClasss()) { 
    // same type -> pass it to subclass implementation 
    return this.subCompare(other) 
    } 

    // different type -> do the comparison here based on Parent's logic 
    // ... 
} 

protected int subCompare(Parent other) 
{ 
    // this should not be called directly 
    return 0; // could throw an exception here too 
} 

// Derived1: 
@Override 
protected int subCompare(Parent other) 
{ 
    // this method is only called from Parent 
    Derived1 other1 = (Derived1) other; 
    // do the comparison based on Derived1's logic 
} 

Аналогично для других производных классов

+0

, вероятно, сделает родительский критерий compare(), чтобы избежать случайных переопределений. в противном случае это работает до тех пор, пока решение не нужно делать на произвольной глубине в иерархии. – jtahlborn

+0

Просто fyi. "this instanceof other.getClasss()" не является корректным оператором в Java ... –

+0

Да, вы просто хотите получить getClass() == other.getClass() " – jtahlborn

0

Это не является прямым ответом на ваш вопрос, но:
Я считаю, что вы делаете, подвержены ошибкам и проблематичны.
Тест на равенство, налагаемый методом compareTo, должен, как правило, возвращать те же результаты, что и метод equals. То есть порядок, наложенный методом compareTo, составляет , если будет соответствовать equals.
Если этот контракт нарушен, вы можете столкнуться с проблемами с сортировкой коллекции (которую вы используете).
Почему я говорю это:
Тот факт, что вы хотите делегировать сравнение с родительским классом в определенных случаях, указывает мне, что вы добавили компонент значения в подкласс.
Если вы сделали это, то нет никакого способа, возможности сохранения equals контракта и вы могли бы работать в задачах с отсортированным контейнером (см.выше)

0

Это собирается быть ошибки так или иначе. Вы могли бы сделать что-то подобное в вашем подклассе:

класса Subclass1 ... {

public boolean equals(Object o) { 
    if(o instanceof Subclass1) { 
    return super.equals(o); 
    } 

    ... compare subclasses 
} 

}

+0

Мне нужно сравнение, а не проверка равенства. –

0

Если иерархия классов будет удлинению или нет?
=> Если он не расширяется (или редко будет расширен), вы можете реализовать Comperator, чтобы весь код сравнения находился в одном месте.

Есть ли несколько способов заказать объекты? => Если да, то вам придется использовать компилятор для каждого заказа.

compareTo(other) (или compare(o1, o2)) вызывается из трех ситуаций:

  1. this instanceof other.class (т.е. o1 instanceof o2.class):
    • это.класс должен сравнивать this и o2, так как он имеет больше информации, чем other.class;
  2. other instanceof this.class (т.е. o2 instanceof o1.class):
    • other.class должны сравнить other и this и this.class.compareTo должны перевернуть результат и вернуть его.
  3. существует первый общего предка P таким образом, что this instanceof P & & other instanceof P:
    • Р следует сравнить this и other: вызов super.compareTo (другой) рекурсивно и возвращает результат.
+0

Это одно из «грязных» решений, о которых я упоминал в своем вопросе. Компаратор должен был бы знать и иметь возможность сравнивать любую комбинацию подклассов, что невозможно, поскольку экземпляры одного и того же подкласса, возможно, должны сравнивать друг друга с помощью частных членов. –

+0

Чтобы избежать комператора, который должен знать все комбинации подкласса, Comperator может быть реализован с использованием аналогичной иерархии, такой как объекты Comparable. Конечно, это не помогает в частном доступе. –

+0

Да, я не думаю, что компаратор - это путь сюда. подумайте, что вы хотите придерживаться Comparable impl. – jtahlborn

0

Это, как я делаю это сейчас. Я думаю, что это так элегантно, как он собирается получить:

public abstract class ParentClass implements Comparable<ParentClass> { 
    // compareTo(ParentClass) is implicitly abstract 
} 


public class SubClass1 extends ParentClass /* Comparable<> is implicitly implemented */ { 
    @Override 
    public int compareTo(ParentClass another) { 
     SubClass1 subAnother = (SubClass1) another; 
     return /* result of sub-class comparison */; 
    } 
} 


public class MyComparator implements Comparator<ParentClass> { 
    @Override 
    public int compare(ParentClass lhs, ParentClass rhs) { 

     // Are lhs and rhs instances of the same sub-class? 
     if(!lhs.getClass().equals(rhs.getClass())) 
      // They are different. Use parent class comparison. 
      return /* result of parent class comparison */; 

     // They are the same. Use sub-class comparison. 
     return lhs.compareTo(rhs); 
    } 
} 

Тогда я просто передать экземпляр MyComparator к TreeMap. Он обрабатывает сравнение между подклассами или передает сравнение с подклассом, если они одинаковы.

Что мне не нравится, так это то, что SubClass1.compareTo() будет бросать ClassCastException, если another является экземпляром другого подкласса. Однако мне не о чем беспокоиться, если я убеждаюсь, что подклассы сравниваются только по MyComparator.

+0

вы можете добавить метод, к которому имеет доступ только MyComperator, переместить текущую реализацию compareTo, а в compareTo вызвать MyComperator.compare. –

+0

@ KaspervandenBerg: Я предпочитаю сохранять compareTo() в подклассах, чтобы он мог получить доступ к закрытым членам. –

+0

Хорошо, я понял, как избежать ClassCastException: Comparable не нужно реализовывать, поскольку compareTo() только когда-либо вызывается MyComparator. Вместо этого я просто сделал compareTo() простой старый защищенный метод в ParentClass. Теперь я могу быть на 100% уверен, что compareTo() будет вызываться только с экземплярами того же класса. –

Смежные вопросы