5. „Any fool can
write code that a
computer can
understand. Good
programmers
write code that
humans can
understand“
Refactoring: Improving the Design of Existing Code, 1999
13. public class Person {
private String firstName;
private String lastName;
private long birthDate;
}
public class Student extends Person {
private int year;
}
public class Professor extends Person {
private String[] specjalities;
}
public class Lecture {
private String title;
private Professor professor;
private Student[] students;
}
Wyobraźmy sobie model...
14. public boolean equals(Object o) {
if (!(o instanceof Person))
return false;
final Person p = (Person) o;
return firstName.equals(p.firstName)
&& lastName.equals(p.lastName)
&& birthDate == p.birthDate;
}
public int hashcode() {
int result = 17;
result = 37*result + firstName.hashCode();
result = 37*result + lastName.hashCode();
result = 37*result + (int)(birthDate ^ birthDate >>> 32);
return result;
}
A teraz piszemy...
15. public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(specjalities);
return result;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof Professor)) {
return false;
}
Professor other = (Professor) obj;
if (!Arrays.equals(specjalities, other.specjalities)) {
return false;
}
return true;
}
lub generujemy...
16. public String toString() {
return "Professor [specjalities=" +
Arrays.toString(specjalities) + "]";
}
to samo tyczy się toString()'a
17. public boolean equals(Object o) {
if (o == null) { return false; }
if (o == this) { return true; }
if (o.getClass() != getClass()) { return false; }
final Student s = (Student) o;
return new EqualsBuilder()
.appendSuper(super.equals(o)).append(year, s.year)
.isEquals();
}
public int hashcode() {
return new HashCodeBuilder(17, 37)
.appendSuper(super.hashcode()).append(year)
.toHashCode();
}
public String toString() {
return new ToStringBuilder(this)
.appendSuper(super.toString()).append("year", year)
.toString();
}
ale przy setce encji się nie chcieć
18. public boolean equals(Object o) {
if (o instanceof Lecture) {
Lecture l = (Lecture) o;
return Objects.equal(professor, l.professor)
&& Objects.equal(students, l.students)
&& Objects.equal(title, l.title);
}
return false;
}
public int hashcode() {
return Objects.hashCode(title, professor, students);
}
public String toString() {
return Objects.toStringHelper(this)
.add("professor", professor)
.add("students", students)
.toString();
}
albo mniej fundamentalnie
19. public void addLectureWithCommons(Lecture lecture, Venue venue,
int dayOfTheWeek, int hour) {
Validate.isTrue(dayOfTheWeek > 0 && dayOfTheWeek <= 7,
"There are only 7 days of the week");
Validate.isTrue(hour >= 0 && hour < 23, "Day has only 24hours");
Validate.notNull(lecture != null, "Lecture cannot be null");
Validate.notNull(venue != null, "Venue cannot be null");
// reminder omitted
}
public void addLectureWithGuava(Lecture lecture, Venue venue,
int dayOfTheWeek, int hour) {
Preconditions.checkArgument(dayOfTheWeek > 0 && dayOfTheWeek <= 7,
"There are only 7 days of the week");
Preconditions.checkArgument(hour >= 0 && hour < 23,
"Day has only 24hours");
Preconditions.checkArgument(lecture != null, "Lecture cannot be null");
Lecture localLecture = Preconditions.checkNotNull(lecture);
Venue localVenue = Preconditions.checkNotNull(venue);
// reminder omitted
}
defensive programming
20. String[] csv;
for (String line : csv) {
String[] elements = line.split(",");
// reminder omitted
}
for (String line : csv) {
String[] r = StringUtils.split(line, ",");
r = StringUtils.stripAll(r);
}
for (String line : csv) {
Splitter.on(",")
.trimResults()
.omitEmptyStrings()
.split(line);
}
a później zawsze trafimy na String'a
21. public interface LectureService {
public Student[] getStudentsByYear(int year);
public Student[] getStudentsOlderThan(int age);
public Student[] getStudentsByBirthDate(Date date);
}
i kilka operacji 'biznesowych'
22. public Student[] getStudentsByYear(int year) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
if (s.getYear() == year) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
które sprowadzają się...
23. public Student[] getStudentsByBirthDate(Date date) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
Calendar studentBirth = Calendar.getInstance();
studentBirth.setTimeInMillis(s.getBirthDate());
Calendar desiredDate = Calendar.getInstance();
desiredDate.setTime(date);
if (studentBirth.get(Calendar.YEAR) ==
desiredDate.get(Calendar.YEAR)
&& studentBirth.get(Calendar.MONTH) ==
desiredDate.get(Calendar.MONTH)
&& studentBirth.get(Calendar.DATE) ==
desiredDate.get(Calendar.DATE)) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
... do niemal ...
24. public Student[] getStudentsOlderThan(int age) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
Calendar c = Calendar.getInstance();
c.setTimeInMillis(s.getBirthDate());
c.add(Calendar.YEAR, age);
Calendar now = Calendar.getInstance();
now.setTime(new Date());
if (c.before(now)) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
... tego samego.
25. public Student[] getStudentsOlderThan(int age) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
DateMidnight dt = new DateMidnight()
.withMillis(s.getBirthDate())
.plusYears(age);
if (dt.isBeforeNow()) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
i abstahując od użycia JodaTime
26. private Student[] getStudents(Predicate predicate) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
if (predicate.evaluate(s)) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
Don't Repeat Yourself
27. Predicate predicate = new Predicate() {
@Override
public boolean evaluate(Object arg0) {
if (arg0 instanceof Student) {
Student s = (Student) arg0;
DateMidnight dt = new DateMidnight()
.withMillis(s.getBirthDate())
.plusYears(age);
if (dt.isBeforeNow()) {
return true;
}
}
return false;
}
};
No a ten predykat?
28. Predicate<Student> predicate = new Predicate<Student>() {
@Override
public boolean apply(Student input) {
DateMidnight dt = new DateMidnight()
.withMillis(input.getBirthDate())
.plusYears(age);
if (dt.isBeforeNow()) {
return true;
}
return false;
}
};
No a ten predykat? (2)
29. private Student[] getStudents(Predicate predicate) {
final List<Student> students = new ArrayList<Student>();
for (Student s : lecture.getStudents()) {
if (predicate.evaluate(s)) {
students.add(s);
}
}
return students.toArray(new Student[] {});
}
i jeszcze na koniec, zamiast...
30. protected Student[] getStudents(Predicate<Student> predicate) {
Iterable<Student> students = Iterables
.filter(Arrays.asList(lecture.getStudents()), predicate);
return Iterables.toArray(students, Student.class);
}
... może być w ogóle ślicznie
31. Student[] students = service.promoteStudents(2);
Predicate<Student> predicate = new Predicate<Student>() {
public boolean apply(Student input) {
if (input.getYear() == year) {
return true;
}
return false;
}
};
Function<Student,Student> function = new Function<Student,Student>(){
public Student apply(Student input) {
input.setYear(year + 1);
return input;
}
};
Iterables.filter();
Iterables.transform();
Jak już jest prawie funkcyjnie...
37. new Person("Ridge", "Forrster");
Person person = new Person.Builder()
.withName(“Ridge”)
.withSurname(“Forrester”)
.build();
Immutability with builders
http://www.marchwicki.pl/blog/2010/11/building-a-pojo-in-an-elegant-way/