java - Implementing interface comparators -


say have simple interface wish comparable based on feature:

interface organism extends comparable<organism> {     string getname();     int getcomplexity();      @override     default int compareto(organism other) {         return this.getcomplexity() - other.getcomplexity();     } } 

each implementing class must return unique complexity 2 instances of class have same complexity , 2 instance of different class have different complexity. natural ordering 'group' instances of classes together.

i want implement interface in class overrides default comparison comparing 2 instance of class within class's group of instances in order. use following pattern:

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'm not particularly happy pattern of code: once set of classes implementing interface becomes large becomes quite complex maintain , requires lots of repeated code , depends on implicit property of 'complexity'. prefer comparator style of defining order. able implement comparable in bacteria using looks like:

return comparator     .comparingint(organism::getcomplexity)     .thencomparing(bacteria::getshape); 

to clear, realise comparators don't work this: designed 1 comparator used across collection, not different comparator depending on each object. mention them here not because potential solution because chaining style of comparators elegant , transparent. i'm interested in whether there's elegant way define compareto allow different orderings within collection depending on class.

i'm not sure plan put comparator. since you'd class implement comparable<organism>, i'll assume you're looking like

class bacteria implements organism {     enum shape {rod, round, 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 won't work, because thencomparing, in context, needs parameter function operates on organism, not bacteria. work around this--i'll leave decide whether elegant enough:

comparator<organism> comparator =      comparator         .comparingint(organism::getcomplexity)         .thencomparing(x -> ((x instanceof bacteria) ? ((bacteria)x).getshape() : shape.rod)); 

in theory, write own method can convert comparator another. can't use instance.method notation, use have this:

comparator<organism> comparator =     mycomparatorutilities.thencomparingifinstanceof(         comparator.comparingint(organism::getcomplexity),         bacteria.class,         bacteria::getshape); 

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

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, don't think approach more readable or maintainable. in fact, believe whole design unmaintainable, because it's easy add class cause comparison violate properties of total ordering; i'd looking different design, starting clearer definition of how want ordering work on objects of different classes. "right" way handle comparisons depend on different design.

for similar problems, might stick compareto approach, unless needed class return comparator other reason (e.g. there multiple orderings defined organisms). however, might ways eliminate duplication, if every compareto if statement same structure, or that.


Comments

Popular posts from this blog

php - Invalid Cofiguration - yii\base\InvalidConfigException - Yii2 -

How to show in django cms breadcrumbs full path? -

ruby on rails - npm error: tunneling socket could not be established, cause=connect ETIMEDOUT -