您是否看过Java中Object类的javadoc? 大概。 您倾向于时不时地到达那里,然后沿着继承树进行挖掘。 您可能已经注意到的一件事是,每个类都必须继承许多方法。 实现自己而不是坚持使用原始方法的最喜欢的方法可能是.toString()、. equals()和.hashCode()( Per-ÅkeMinborg在本文中很好地描述了为什么应该始终实现这两种方法) )。
但是这些方法显然还不够。 许多人从标准库(如Comparable和Serializable)中混合使用其他接口。 但这真的很明智吗? 为什么每个人都想如此严重地自己实现这些方法? 好吧,如果您打算将它们存储在HashMap之类的文件中并希望控制哈希冲突,那么实现自己的.equals()和.hashCode()方法可能会很有意义,但是compareTo()和toString()呢?
在本文中,我将介绍一种在Speedment开源项目中使用的软件设计方法,其中将对对象进行操作的方法实现为存储在变量中的功能引用,而不是覆盖内置在方法中的Java。 这有几个优点。 您的POJO将更短,更简洁,可以重复使用通用操作而无需继承,并且可以灵活地在不同配置之间进行切换。
原始码
让我们从下面的示例开始。 我们有一个典型的Java类,名为Person。 在我们的应用程序中,我们希望按Set的顺序打印每个人的名字,其后跟姓氏(以防两个人共享相同的名字)。
人.java
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
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);
}
}
输出量
run:
Adam Johnsson
Adam Samuelsson
Ben Carlsson
Cecilia Adams
BUILD SUCCESSFUL (total time: 0 seconds)
Person在此处实现了几种方法来控制流的输出。 hashCode()和equals()方法确保不能将重复的人添加到集合中。 sorted操作使用compareTo()方法产生所需的顺序。 重写的toString()方法最终控制了在调用System.out.println()时应如何打印每个Person。 您认识这种结构吗? 您几乎可以在几乎所有的Java项目中找到它。
替代代码
除了将所有功能都放入Person类之外,我们还可以尝试使其尽可能保持清洁,并使用功能性引用来处理这些修饰。 我们使用equals,hashCode,compareTo和toString删除所有样板,而是引入两个静态变量COMPARATOR和TO_STRING。
人.java
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
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);
}
}
输出量
run:
Adam Johnsson
Adam Samuelsson
Ben Carlsson
Cecilia Adams
BUILD SUCCESSFUL (total time: 0 seconds)
这种方法的好处是,我们现在可以在不更改Person类的情况下替换打印的顺序和格式。 这将使代码更易于维护,更易于重用,而不是说编写起来更快。