Reputation: 40398
Imagine that I have a domain object with an enum named SortBy
to facilitate sorting of the data from the service and / or dao layer.
public class Item {
public static enum SortBy { CATEGORY, NORWEGIAN, ENGLISH; }
private String category;
private String norwegian;
private String English;
}
This sort of operation is therefore possible: itemDao.getItems(Item.SortBy.CATEGORY)
Now, is there a design pattern or nice way to relate the SortBy
values to java Comparator
's?
I am asking this since the ways I initially thought about used static
, and that's bad practise (right?).
A Map<SortBy, Comparator<Item>
in the Item class?
A class ItemComparators
with method getComparator(Item.SortBy sort)
?
A method on the SortBy
enum itself that returns a static instance of Comparator<Item>
?
I'm looking for a minimalist way to do this, without going so far as to have a ItemComparatorProvider
bean.
Appreciate any information...
Upvotes: 1
Views: 1235
Reputation: 25623
The most straightforward way to do this is to simply have the enum
itself implement Comparator
:
public enum SortBy implements Comparator<Item> {
CATEGORY {
@Override
public final int compare(final Item o1, final Item o2) {
return compareStrings(o1.getCategory(), o2.getCategory());
}
},
ENGLISH {
@Override
public final int compare(final Item o1, final Item o2) {
return compareStrings(o1.getEnglish(), o2.getEnglish());
}
},
NORWEGIAN {
@Override
public final int compare(final Item o1, final Item o2) {
return compareStrings(o1.getNorwegian(), o2.getNorwegian());
}
};
private static int compareStrings(final String s1, final String s2) {
if (s1 == null) {
return s2 == null ? 0 : -1;
}
if (s2 == null) {
return 1;
}
return s1.compareTo(s2);
}
}
There's no need to further associate each enum member with a comparator because the enum members are the comparators. The usage is then nice and concise:
Collections.sort(items, SortBy.CATEGORY);
Addendum
In the comments below, you asked about common, null
-safe comparisons. I'm not sure what third-party libraries might provide them, but you can implement them yourself easily enough. Here's two from one of our internal libraries:
static <T extends Comparable<? super T>> int compare(final T o1, final T o2) {
if (o1 == null) {
return o2 == null ? 0 : -1;
}
if (o2 == null) {
return 1;
}
return o1.compareTo(o2);
}
@SuppressWarnings("unchecked")
static int compare(final Object a, final Object b) {
if (a == b) {
return 0;
}
if (a == null) {
return -1;
}
if (b == null) {
return 1;
}
final Class<?> aClass = a.getClass();
final Class<?> bClass = b.getClass();
if (Comparable.class.isInstance(a) && aClass.isAssignableFrom(bClass)) {
return ((Comparable<Object>)a).compareTo(b);
}
if (Comparable.class.isInstance(b) && bClass.isAssignableFrom(aClass)) {
return ((Comparable<Object>)b).compareTo(a);
}
throw new IllegalArgumentException("Values must be comparable.");
}
Upvotes: 4
Reputation: 30538
You can think about something like this:
public static enum SortBy {
CATEGORY(new CategoryComparator()), NORWEGIAN(new NorwegianComparator()), ENGLISH(new EnglishComparator());
Comparator<Item> comparator;
private SortBy(Comparator<Item> comparator) {
this.comparator = comparator;
}
}
You can either implement Comparator
and create new classes if you will use them elsewhere or implement them as anonymous inner classes like in vikingsteve's answer.
Upvotes: 2
Reputation: 40398
Ok well here is one way to do it. Is this fine?
public static enum SortBy {
CATEGORY(new Comparator<Item>() {
@Override
public int compare(Item o1, Item o2) {
return o1.getCategory().compareTo(o2.getCategory());
}
}),
NORWEGIAN(new Comparator<Item>() {
@Override
public int compare(Item o1, Item o2) {
return o1.getNorwegian().compareTo(o2.getNorwegian());
}
}),
ENGLISH(new Comparator<Item>() {
@Override
public int compare(Item o1, Item o2) {
return o1.getEnglish().compareTo(o2.getEnglish());
}
});
private Comparator<Item> comparator;
private SortBy(Comparator<Item> comparator) {
this.comparator = comparator;
}
public Comparator<Item> getComparator() {
return comparator;
}
}
Upvotes: 1