我的应用程序可以比较同一抽象父类的任何两个子类的实例。我希望它们进行如下比较:
- 如果它们是不同的子类,则应由父类进行比较。
- 如果它们是相同的子类,则子类应该进行比较。
这些类将通过 TreeMap 进行比较,因此我可以选择使用 Comparator 或实现 Comparable(或两者兼而有之?)。
我可以想到几种方法来做到这一点,但它们都有些混乱且容易出错。有没有优雅的解决方案?
提前致谢...
我的应用程序可以比较同一抽象父类的任何两个子类的实例。我希望它们进行如下比较:
这些类将通过 TreeMap 进行比较,因此我可以选择使用 Comparator 或实现 Comparable(或两者兼而有之?)。
我可以想到几种方法来做到这一点,但它们都有些混乱且容易出错。有没有优雅的解决方案?
提前致谢...
你可以试试
// 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
}
对于其他派生类也是如此
这不是您问题的直接答案,但是:
我相信您所做的事情容易出错且有问题。
方法强加的相等性测试compareTo
通常应该返回与方法相同的结果equals
。即compareTo
方法强加的排序应该与 一致equals
。
如果违反此合同,您可能会遇到排序集合(您正在使用)的问题。
为什么我这样说:
在某些情况下您希望将比较委托给父类这一事实向我表明您在子类中添加了一个值组件。
如果你这样做了,那么就没有办法保存equals
合同,您可能会遇到排序容器的问题(见上文)
无论哪种方式,它都容易出错。你可以在你的子类中做这样的事情:
类子类1 ... {
public boolean equals(Object o) {
if(o instanceof Subclass1) {
return super.equals(o);
}
... compare subclasses
}
}
类层次结构是否应该可扩展?
=> 如果它不可扩展(或很少会扩展),您可以实现一个 Comperator 以便所有比较代码都在一个地方。
订购对象的方法不止一种吗?=> 如果是这样,那么您将不得不为每个订单使用一个比较器。
compareTo(other)
(或compare(o1, o2)
)从三种情况中调用:
this instanceof other.class
(即o1 instanceof o2.class
):
this
,o2
因为它比 other.class 有更多的信息;other instanceof this.class
(即o2 instanceof o1.class
):
other
并且this
this.class.compareTo 应该翻转结果并返回它。this instanceof P
&& other instanceof P
:
this
and other
: 递归调用 super.compareTo(other) 并返回结果。这就是我现在的做法。我认为这将变得非常优雅:
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
ifanother
是另一个子类的实例。但是,只要我确保子类仅按MyComparator
.