Sometimes we need to sort a list of menu-items after a list of label-strings. That means, the template list contains elements of another data-type than the list to be sorted after the template list.
Example
Here is a simplified MenuItem
class:
public class MenuItem { public final String label; public MenuItem(String label) { this.label = Objects.requireNonNull(label); } @Override public String toString() { return label; } }
And here is a template list that contains String
objects
instead of MenuItem
:
public static final String CUT = "Cut"; public static final String COPY = "Copy"; public static final String PASTE = "Paste"; final List<Object> sorted = List.of( CUT, COPY, PASTE);
Can we sort a list of MenuItem
after that list of String
?
Generic Comparator
Yes we can ;-)
We need a generic extension of TemplateDrivenComparator
(see my latest article for that class):
/** * Serves to sort lists where the template-list * has a different type than the list to sort. */ public abstract class GenericTemplateDrivenComparator extends TemplateDrivenComparator<Object> { @Override public int compare(Object o1, Object o2) { return super.compare(convert(o1), convert(o2)); } protected abstract Object convert(Object object); }
This comparator uses the generic <Object>
as data-type for list elements.
It then overrides the compare()
responsibility
to convert each of the given parameters to a possibly different object before calling
super.compare()
.
That way any MenuItem
parameter can be converted to a String
,
which is necessary for super.compare()
to work correctly.
Here is an example application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public class Main { public static final String CUT = "Cut"; public static final String COPY = "Copy"; public static final String PASTE = "Paste"; public static void main(String[] args) { final List<MenuItem> sequence = new ArrayList<>(); sequence.add(new MenuItem(COPY)); sequence.add(new MenuItem(PASTE)); sequence.add(new MenuItem(CUT)); System.out.println(sequence); final Comparator<Object> comparator = new GenericTemplateDrivenComparator() { private final List<Object> sorted = List.of( CUT, COPY, PASTE); @Override protected List<Object> template() { return sorted; } @Override protected Object convert(Object object) { return (object instanceof MenuItem) ? ((MenuItem) object).label : object; } }; Collections.sort(sequence, comparator); System.out.println(sequence); } } |
Lines 3 - 5 define the labels.
The main()
procedure on line 7 builds a sequence of menu-items from that labels,
which is to be sorted.
It prints out the menu-item list on line 12.
Lines 14 - 30 define an anonymous comparator class that is made up to sort menu-items after a template list of strings. We see the template list on line 16 - 20, returned on line 24.
The convert()
function on ine 27 - 29
uses the instanceof
operator to find out of which data-type the given parameter is.
In case it is a MenuItem
, it returns its label,
else it returns the template String
directly.
Line 32 finally sorts the list of menu-items (physically).
Output of the application is:
[Copy, Paste, Cut] [Cut, Copy, Paste]
Resume
Unfortunately I did not find a way how to implement this
without using the instanceof
operator.
The Visitor pattern should be helpful in such cases, but ...
Keine Kommentare:
Kommentar veröffentlichen