假设我有一个简单的界面,我希望基于某些功能可比较:
interface Organism extends Comparable<Organism> {
    String getName();
    int getComplexity();

    @Override
    default int compareto(Organism other) {
        return this.getComplexity() - other.getComplexity();
    }
}

每个实现类必须返回唯一的复杂性,因此类的任何两个实例将具有相同的复杂性,并且不同类的任何两个实例将具有不同的复杂性.自然排序将所有类的实例“组合”在一起.

我现在想要在一个类中实现此接口,该类重写默认比较,专门用于比较该类的实例组中该类的两个实例.我使用以下模式:

class Bacteria implements Organism {
    enum Shape {ROD,ROUND,Spiral};
    private final Shape shape;

    @Override
    public int compareto(Organism other) {
        if (other instanceof Bacteria)
            return this.shape.compareto((Bacteria)other.shape);
        else
            return Organism.super.compareto(other);
    }
}

我对这种代码模式并不是特别满意:一旦实现接口的类集变得很大,维护变得非常复杂并且需要大量重复的代码并依赖于“复杂性”的隐含属性.我更喜欢定义订单的比较器风格.我希望能够使用看起来像这样的东西来实现细菌中的Comparable:

return Comparator
    .comparingInt(Organism::getComplexity)
    .thenComparing(Bacteria::getShape);

为了清楚起见,我意识到比较器不能像这样工作:它们被设计成在一个集合中使用一个比较器,而不是根据每个对象使用不同的比较器.我在这里提到它们并不是因为它们是一种潜在的解决方案,而是因为比较器的链式风格优雅而透明.我感兴趣的是,是否有一种同样优雅的方式来定义compareto以允许集合中的不同排序取决于类.

解决方法

我不确定你打算把比较器放在哪里.既然你希望你的班级实现Comparable< Organism>,我会假设你正在寻找像
class Bacteria implements Organism {
    enum Shape {ROD,Spiral};
    private final Shape shape;

    Comparator<Organism> comparator = 
        Comparator
            .comparingInt(Organism::getComplexity)
            .thenComparing(Bacteria::shape);  // illegal

    @Override
    public int compareto(Organism other) {
        return comparator.compare(this,other);
    }
}

这不起作用,因为在上下文中,比较需要一个参数,该参数是一个在生物上运行的函数,而不是一个细菌.你可以像这样解决它 – 我会留给你判断这是否足够优雅:

Comparator<Organism> comparator = 
    Comparator
        .comparingInt(Organism::getComplexity)
        .thenComparing(x -> ((x instanceof Bacteria) ? ((Bacteria)x).getShape() : Shape.ROD));

理论上,您也可以编写自己的方法,将比较器转换为另一个.你不能使用instance.method表示法,所以使用必须是这样的:

Comparator<Organism> comparator = 
   MyComparatorUtilities.thenComparingIfInstanceOf(
        Comparator.comparingInt(Organism::getComplexity),Bacteria.class,Bacteria::getShape);

thenComparingIfInstanceOf的以下实现编译(并允许上面的代码编译),但我还没有尝试测试它:

class MyComparatorUtilities {
    public static 
    <T,U extends T,V extends Comparable<? super V>> Comparator<T> thenComparingIfInstanceOf(
        Comparator<T> comparator,Class<U> subclass,Function<? super U,? extends V> keyExtractor) {
        return (a,b) -> {
            int comp = comparator.compare(a,b);
            if (comp != 0) {
                return comp;
            }
            if (subclass.isinstance(a) && subclass.isinstance(b)) {
                return keyExtractor.apply(subclass.cast(a))
                    .compareto(keyExtractor.apply(subclass.cast(b)));
            }
            return 0;
        };
    }
}

更多:回答评论:不,我不一定认为这种方法更具可读性或可维护性.事实上,我认为整个设计是不可维护的,因为添加一个会导致比较违反总排序属性的类太容易了;我正在寻找一种不同的设计,从更明确的定义开始,我希望订单如何处理不同类的对象.处理比较的“正确”方式可能取决于不同的设计.

对于类似的问题,我可能会坚持使用compareto方法,除非我因为某些其他原因需要一个类来返回Comparator(例如,为Organisms定义了多个排序).但是,如果每个compareto都是具有相同结构的if语句,或者类似的东西,我可能会寻找消除重复的方法.

java – 实现接口比较器的更多相关文章

  1. delphi – 对于静态数组,使用RTTI获取记录字段的类型失败

    我正在尝试获取记录字段的类型以创建正确的比较器.我找不到静态数组的类型信息:对于任何类型的静态数组,FieldType都是nil.任何想法在这里有什么问题?或者也许有更简单的方法来创建与TArray/TDictionary等一起使用的记录的比较器?解决方法您需要声明一个类型才能使RTTI可用.例如:

  2. delphi – 如何使一个类似Excel的A排序,然后通过B在TObjectList &lt;&gt;中使用多个比较器

    首先,我做了一个基类TSortCriterion和一个TSortCriteriaComparer,以便将来可以在多个类中使用这些。我将Criterion和列表分别更改为TObject和TObjectList,因为如果objectlist自动处理Criterion的销毁,我发现它更容易。Comparer成员将根据名称和年龄参考您已经编写的用于比较的功能。现在写一个引用该列表的单一比较函数。

  3. delphi – 如何使用自定义比较器排序通用列表?

    我有一个Delphi-newbie,我不知道如何调用记录TList的Sort方法,以便通过递增整数值对记录进行排序。我有一个记录如下:和这样的记录的通用列表:尝试在帮助文件中找到一个代码示例,并找到了一个:我不能使用,因为它使用类。解决方法应该使用的Sort重载是这个:现在,您可以创建一个IComparer通过调用TComparer.Construct。调用TComparer.Default可能是昂贵的,您可以将其存储在全局变量中:要考虑的另一个选择是在创建列表时传入比较器。

  4. 带有自定义匿名比较器的Java Priority Queue

    我在网上看了一些例子,但我能找到的只是字符串优先级队列.我可以为Node类实现Comparator吗?这会允许我访问存储在其中的数据成员吗?解决方法绝对.您可以使用基于传递给构造函数的匿名Comparator的PriorityQueue:如果您的Node类已经实现了Comparable,您甚至不需要定义新的Comparator,因为默认情况下将使用该顺序.除非采用任何其他方法,否则将使用对象之间的自然顺序.

  5. 如何正确使用Java比较器?

    如果我有以下课程:如何使用按名称比较的比较器,然后是年龄,然后是id?解决方法您需要实现它,以便按首选元素进行排序.也就是说,您需要按名称进行比较,然后如果该比较相等,则按年龄等进行比较.下面列出了一个示例:

  6. java – 基于可配置顺序的比较器

    有没有办法写自定义比较器,下面这个例子:最多有10个项目以随机顺序进入即我想要使它们排序像:second_one,third_one,first_one.我想从配置文件中提取这个顺序,就像用于排序的模板一样.我使用错误的数据结构,有没有人有这方面的经验?解决方法当然.这是一个“OrderedComparator”,它根据预定义的顺序对元素进行比较:这里是一些测试代码.在讨论元素的顺序时看起来更自然,2)更好地说明在使用此比较器进行排序时重复元素会发生什么.)输出:

  7. java – 实现接口比较器

    假设我有一个简单的界面,我希望基于某些功能可比较:每个实现类必须返回唯一的复杂性,因此类的任何两个实例将具有相同的复杂性,并且不同类的任何两个实例将具有不同的复杂性.自然排序将所有类的实例“组合”在一起.我现在想要在一个类中实现此接口,该类重写默认比较,专门用于比较该类的实例组中该类的两个实例.我使用以下模式:我对这种代码模式并不是特别满意:一旦实现接口的类集变得很大,维护变得非常复杂并且需要大量

  8. javascript – 基于java脚本中嵌套对象数组中的键对列表进行排序的最佳方法

    我有以下内容:假设我有上面的变量列表,我该如何对其进行排序,使得列表中具有项密钥的所有直接对象基于密钥按升序排序.请注意,它不会更改或重新排序list[x][“item”]中的列表,而只会更改list[x]中的直接项.标准排序函数似乎只对数组中对象内的键进行排序,但我想根据位于数组中嵌套对象中的键进行排序.排序这个的最佳方法是什么?

  9. c# – 在HashSet上调用Distinct &lt;&gt;()

    我只是很好奇..当我在HashSet上调用distinct()时,.NET是否知道,这个IEnumerable总是包含不同的值集,并优化了这个调用?

  10. java – 比较器必须覆盖超类方法

    我正在制作一个TreeMap并希望以降序排列.我创建了以下比较器:我构建了TreeMap,如下所示:myMap=newTreeMap;但是,我收到以下错误:我从来没有完全摸索仿制药,我做错了什么?解决方法您的Eclipse项目显然设置为Java1.5.接口方法确实不支持@Override注释.删除该注释或将项目的合规级别修复到Java1.6.

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部