我想知道是否可以将两个比较器组合成一个比较器,用于两个完全不同的类。对象将按字母顺序按字符串类型name
属性进行排序,该属性存在于两个类中,这就是我创建单个比较器的原因。
/**
* Comparator to sort Book or Magazine alphabetically based on
* their String type name property.
*/
public class BookOrMagazineComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
if (o1 != null && o2 != null) {
if (o1 instanceof Book && o2 instanceof Book) {
Book b1 = (Book) o1;
Book b2 = (Book) o2;
return b1.getName().compareTo(b2.getName());
} else if (o1 instanceof Magazine && o2 instanceof Magazine) {
Magazine m1 = (Magazine) o1;
Magazine m2 = (Magazine) o2;
return m1.getName().compareTo(m2.getName());
}
}
return 0;
}
}
如果我使用上述方法会有任何副作用吗?
编辑:我想补充一点,Book / Magazine实际上是枚举。
答案 0 :(得分:6)
这是基于意见的,但我称之为不好的做法,因为它打破了每个班级只应服务于一个目的的规则(AKA Single Responsibility principle)。
此外它可能已被破坏,因为如果您在Magazine
和Book
旁边传递任何内容(例如InputStream
和URL
以举例说明),则会返回0
意思是他们是平等的。你通过实施Comparator<Object>
而放弃了类型安全,这是一种耻辱。
正如评论中所建议的,找到你关心的两个类的通用接口并为该接口实现比较器是个好主意。在这种情况下,它将是完美的意义。
建议:您说这些课程是无关的,但它们有一些共同之处 - name
如果您有NamedItem
接口Magazine
和{{} 1}}实现你可以创建Book
,你就可以了。
注意:您添加的类是枚举。没问题。 Enum can easily implement interface
答案 1 :(得分:1)
如果我使用上述方法会有任何副作用吗?
是。紧耦合。您的比较器类将依赖于它引用的每个类。这将是重复使用的轻微障碍,因为如果没有它引用的类,它将无法存在。
正如另一个答案所指出 - 一个班级应该只服务于一个目的。那是single responsibility principle,这种做法略微违反了这一原则。
答案 2 :(得分:1)
当你这样做时,你会失去很多Java类型的安全性。
比较类型为Comparator<Book>
的比较器的一大好处是,如果我有List<DVD>
,我不会意外地尝试使用该比较器对其进行排序;编译器甚至不会让我。但是根据您的方法,我的列表可以是任何的列表:书籍,DVD,船等。如果列表恰好是所有书籍的列表或所有杂志的列表在运行时间,我可能会得到令人惊讶的行为。
请注意,您的比较器会破坏传递性。如果我有一本书{Aaa},一本杂志{Bbb}和一本书{Ccc},那么:
return 0
如果你解决了这个问题(例如,通过在方法的末尾抛出异常而不是返回0),那么令人惊讶的行为是排序将崩溃,除非你有一个同类的书籍或杂志列表。如果你保留了破损的合同,那么令人惊讶的行为是未定义的,并且可能会导致一个未正确排序的列表(因为排序算法会假设它需要比较哪些元素,只有当比较器是传递的)。
答案 3 :(得分:0)
是的,不建议这样做。此外,您只是将“杂志”与“杂志”和“反对书籍”进行比较。
如果说,您只打算通过名称或类似属性比较这些不同类中的对象,您可以使用层次结构并按基类类型进行比较:
class ReadingMaterial
{
protected String name;
//other attributes here..
}
class Magazine extends ReadingMaterial
{
}
class Book extends ReadingMaterial
{
}
现在您只需要实现Comparator一次,而不是为所有类型实现它:
class ReadingMaterialComparator implements Comparator<ReadingMaterial>
{
//implements comparison here..
}
使用上述方法,即使您需要添加新类型的ReadingMaterial,例如NewsPaper
。您甚至不必编辑比较器,它仍然可以工作。实质上,它使您的实施 更具可扩展性 和 更少耦合 。