Мы играем немного больше с библиотекой 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 Дэна Хейвуда в блоге Дэна Хейвуда .