Мы играем немного больше с библиотекой Google Guava — какая замечательная библиотека! Самое последнее, для чего мы его использовали, — это сортировка компараторов для наших доменных объектов. Вот как. Используя Apache Isis ‘ JDO Objectstore , рекомендуется, чтобы ваши классы реализовывали java.lang.Comparable и использовали SortedSet для коллекций. Вы можете увидеть это в ToDoItem архетипа Isis, где ToDoItem имеет рекурсивное отношение к себе:
|
1
2
3
4
5
|
public class ToDoItem implements Comparable<ToDoItem> { ... private SortedSet<ToDoItem> dependencies = Sets.newTreeSet(); ...} |
Как лучше всего реализовать метод compareTo ? Вот оригинальная реализация:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
public int compareTo(final ToDoItem other) { if (isComplete() && !other.isComplete()) { return +1; } if (!isComplete() && other.isComplete()) { return -1; } if (getDueBy() == null && other.getDueBy() != null) { return +1; } if (getDueBy() != null && other.getDueBy() == null) { return -1; } if (getDueBy() == null && other.getDueBy() == null || getDueBy().equals(this.getDueBy())) { return getDescription().compareTo(other.getDescription()); } return getDueBy().compareTo(getDueBy());} |
Юк! В основном это говорит:
* заказать еще не завершенные объекты перед завершенными объектами
* там, где есть связь, заказ по дате выполнения (поместите те без даты по дате в последнюю очередь)
* где есть галстук, порядок по описанию.
Вот как это переписать, используя класс Order в Guava. Сначала давайте создадим несколько экземпляров Ordering для скалярных типов:
|
01
02
03
04
05
06
07
08
09
10
11
|
public final class Orderings { public static final Ordering<Boolean> BOOLEAN_NULLS_LAST = Ordering.<Boolean>natural().nullsLast(); public static final Ordering<LocalDate> LOCAL_DATE_NULLS_LAST = Ordering.<LocalDate>natural().nullsLast(); public static final Ordering<String> STRING_NULLS_LAST = Ordering.<String>natural().nullsLast(); private Orderings(){}} |
Теперь мы можем переписать ToDoItem compareTo() декларативным способом:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public class ToDoItem implements Comparable { ... public int compareTo(ToDoItem o) { return ORDERING_BY_COMPLETE .compound(ORDERING_BY_DUE_BY) .compound(ORDERING_BY_DESCRIPTION) .compare(this, o); } public static Ordering<ToDoItem> ORDERING_BY_COMPLETE = new Ordering<ToDoItem>(){ public int compare(ToDoItem p, ToDoItem q) { return Orderings.BOOLEAN_NULLS_LAST.compare(p.isComplete(), q.isComplete()); } }; public static Ordering<ToDoItem> ORDERING_BY_DUE_BY = new Ordering()<ToDoItem>{ public int compare(ToDoItem p, ToDoItem q) { return Orderings.BOOLEAN_NULLS_LAST.compare(p.getDueBy(), q.getDueBy()); } }; public static Ordering<ToDoItem> ORDERING_BY_DESCRIPTION = new Ordering()<ToDoItem>{ public int compare(ToDoItem p, ToDoItem q) { return Orderings.STRINGS_NULLS_LAST.compare( p.getDescription(), q.getDescription()); } }; |
Теперь, по общему признанию, это вряд ли оправдывает весь этот шаблон для только одного метода в одном классе; конечно нет! Но сейчас у нас есть небольшая алгебра, которую мы можем использовать для объединения всех классов предметной области в нашей предметной модели. Другие классы домена, использующие ToDoItem могут упорядочивать себя, используя естественное упорядочение ToDoItem (доступное из Ordering.natural() ), или они могут создавать новые упорядочения, используя различные упорядочения ToDoItem.ORDERING_BY_xxx .
Ссылка: используя Google Guava Ordering API от нашего партнера JCG Дэна Хейвуда в блоге Дэна Хейвуда .