Вы когда-нибудь смотрели на javadoc Object-класса в Java? Вероятно. Вы склонны в конечном итоге оказаться там и сейчас, когда копаете свой путь вниз по дереву наследования. Одна вещь, которую вы, возможно, заметили, состоит в том, что в ней есть несколько методов, которые каждый класс должен наследовать. Вероятно, любимые методы реализации себя, а не использования оригинальных, — это .toString (), .equals () и .hashCode () (почему всегда следует реализовывать оба последних, хорошо описано Per-Åke Minborg в этом посте. ).
Но этих методов явно недостаточно. Многие люди используют дополнительные интерфейсы из стандартных библиотек, таких как Comparable и Serializable . Но действительно ли это мудро? Почему все так сильно хотят реализовать эти методы самостоятельно? Что ж, реализация ваших собственных методов .equals () и .hashCode (), вероятно, будет иметь смысл, если вы планируете хранить их в чем-то вроде HashMap и хотите контролировать коллизии хешей, но как насчет CompareTo () и toString ()?
В этой статье я представлю подход к проектированию программного обеспечения, который мы используем в проекте с открытым исходным кодом Speedment, где методы, которые работают с объектами, реализуются как функциональные ссылки, хранящиеся в переменных, а не переопределяют встроенные методы Javas. В этом есть несколько преимуществ. Ваши POJO будут короче и более краткими, общие операции могут быть повторно использованы без наследования, и вы можете гибко переключаться между различными конфигурациями.
Оригинальный код
Давайте начнем с рассмотрения следующего примера. У нас есть типичный класс Java с именем Person. В нашем приложении мы хотим распечатать каждого человека из набора в порядке его имени, за которым следует фамилия (в случае, если два человека имеют одно и то же имя).
Person.java
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
public class Person implements Comparable<Person> { private final String firstname; private final String lastname; public Person(String firstname, String lastname) { this .firstname = firstname; this .lastname = lastname; } public String getFirstname() { return firstname; } public String getLastname() { return lastname; } @Override public int hashCode() { int hash = 7 ; hash = 83 * hash + Objects.hashCode( this .firstname); hash = 83 * hash + Objects.hashCode( this .lastname); return hash; } @Override public boolean equals(Object obj) { if ( this == obj) return true ; if (obj == null ) return false ; if (getClass() != obj.getClass()) return false ; final Person other = (Person) obj; if (!Objects.equals( this .firstname, other.firstname)) { return false ; } return Objects.equals( this .lastname, other.lastname); } @Override public int compareTo(Person that) { if ( this == that) return 0 ; else if (that == null ) return 1 ; int comparison = this .firstname.compareTo(that.firstname); if (comparison != 0 ) return comparison; comparison = this .lastname.compareTo(that.lastname); return comparison; } @Override public String toString() { return firstname + " " + lastname; } } |
Main.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public class Main { public static void main(String... args) { final Set people = new HashSet<>(); people.add( new Person( "Adam" , "Johnsson" )); people.add( new Person( "Adam" , "Samuelsson" )); people.add( new Person( "Ben" , "Carlsson" )); people.add( new Person( "Ben" , "Carlsson" )); people.add( new Person( "Cecilia" , "Adams" )); people.stream() .sorted() .forEachOrdered(System.out::println); } } |
Выход
1
2
3
4
5
6
|
run: Adam Johnsson Adam Samuelsson Ben Carlsson Cecilia Adams BUILD SUCCESSFUL (total time: 0 seconds) |
Человек реализует несколько методов здесь, чтобы управлять выводом потока. Методы hashCode () и equals () обеспечивают невозможность добавления дубликатов в набор. Метод compareTo () используется отсортированным действием для получения желаемого порядка. Переопределенный метод toString (), наконец, контролирует, как должен выводиться каждый объект Person при вызове System.out.println (). Вы узнаете эту структуру? Вы можете найти его почти в каждом Java-проекте.
Альтернативный код
Вместо того, чтобы помещать всю функциональность в класс Person, мы можем постараться сохранить его как можно более чистым и использовать функциональные ссылки для обработки этих украшений. Мы удаляем весь шаблон с помощью equals, hashCode, compareTo и toString и вместо этого вводим две статические переменные, COMPARATOR и TO_STRING.
Person.java
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
|
public class Person { private final String firstname; private final String lastname; public Person(String firstname, String lastname) { this .firstname = firstname; this .lastname = lastname; } public String getFirstname() { return firstname; } public String getLastname() { return lastname; } public final static Comparator<Person> COMPARATOR = Comparator.comparing(Person::getFirstname) .thenComparing(Person::getLastname); public final static Function<Person, String> TO_STRING = p -> p.getFirstname() + " " + p.getLastname(); } |
Main.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public class Main { public static void main(String... args) { final Set people = new TreeSet<>(Person.COMPARATOR); people.add( new Person( "Adam" , "Johnsson" )); people.add( new Person( "Adam" , "Samuelsson" )); people.add( new Person( "Ben" , "Carlsson" )); people.add( new Person( "Ben" , "Carlsson" )); people.add( new Person( "Cecilia" , "Adams" )); people.stream() .map(Person.TO_STRING) .forEachOrdered(System.out::println); } } |
Выход
1
2
3
4
5
6
|
run: Adam Johnsson Adam Samuelsson Ben Carlsson Cecilia Adams BUILD SUCCESSFUL (total time: 0 seconds) |
С этим подходом приятно то, что теперь мы можем заменить порядок и формат печати, не изменяя наш класс Person. Это сделает код более легким в обслуживании и более легким для повторного использования, не говоря уже о более быстром написании.
Ссылка: | Ответственность за чистоту — избавьтесь от равенства, сравнения и toString от нашего партнера по JCG Эмиля Форслунда из блога Age of Java . |