Java – implement interface comparator

Assuming I have a simple interface, I want to compare based on some functions:

interface Organism extends Comparable<Organism> {
    String getName();
    int getComplexity();

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

Each implementation class must return a unique complexity, so any two instances of the class will have the same complexity, and any two instances of different classes will have different complexity Natural sorting "groups" instances of all classes together

I now want to implement this interface in a class that overrides the default comparison and is specifically used to compare two instances of the class in the instance group of the class I use the following modes:

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);
    }
}

I am not particularly satisfied with this code pattern: once the class set of the implementation interface becomes large, the maintenance becomes very complex, requires a lot of repeated code, and depends on the implicit attribute of "complexity" I prefer the comparator style of defining orders I want to be able to use something like this to achieve comparable in bacteria:

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

For the sake of clarity, I realize that comparators cannot work like this: they are designed to use one comparator in a collection, rather than using different comparators according to each object I mention them here not because they are a potential solution, but because the chain style of the comparator is elegant and transparent I am interested in whether there is an equally elegant way to define CompareTo to allow different sorting in the collection depends on the class

Solution

I'm not sure where you're going to put the comparator Since you want your class to achieve comparable < organization >, I will assume that you are looking for something like

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);
    }
}

This doesn't work because in the context, the comparison requires a parameter, which is a function running on a organism, not a bacterium You can solve it like this – I'll leave it to you to judge whether it's elegant enough:

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

Theoretically, you can also write your own method to convert the comparator to another You cannot use instance Method notation, so it must be used as follows:

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

The following implementation of thencomparingifinstanceof compiles (and allows the above code to compile), but I haven't tried to test it yet:

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;
        };
    }
}

More: answer comment: No, I don't necessarily think this method is more readable or maintainable In fact, I think the whole design is not maintainable, because it is too easy to add a class that will lead to a comparison violation of the total sorting attribute; I'm looking for a different design, starting with a clearer definition of how I want orders to deal with different classes of objects The "right" way to handle comparisons may depend on different designs

For similar problems, I may insist on using the CompareTo method unless I need a class to return comparator for some other reason (for example, multiple sorts are defined for organizations) However, if each CompareTo is an IF statement with the same structure, or something like that, I may look for ways to eliminate duplication

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>