In the last year or so, I've finally been able to write object-oriented code. I first learned about object-orientation in 1995, so it took me more than 20 years.
The reason why I became able to write object-oriented code This is because I tried to write with the Value Object in mind.
The simplest definition is the translation of the article written by Dr. Martin Fowler (Value Object) [^ 1].
In the case of Java, it is good to satisfy the following two. It's not directly related, but it also implements toString ().
For example, let's implement a [java.time.Year] [] -like class, MyYear. Since it is troublesome to implement equals () and hashCode () properly, I leave it to the IDE (IntelliJ IDEA).
public final class MyYear {
private final int year;
private MyYear(int year) {
this.year = year;
}
public static MyYear of(int year) {
return new MyYear(year);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyYear myYear = (MyYear) o;
return year == myYear.year;
}
@Override
public int hashCode() {
return year;
}
@Override
public String toString() {
return "MyYear{" +
"year=" + year +
'}';
}
}
You can also use Apache Commons Lang for your implementation. It uses reflection, but the description is simple. (Some APIs do not use reflection)
The reason why SHORT_PREFIX_STYLE is used for toString () is You don't need the hash code for the object, you only need the value of the field.
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public final class MyYear {
private final int year;
private MyYear(int year) {
this.year = year;
}
public static MyYear of(int year) {
return new MyYear(year);
}
@Override
public boolean equals(Object o) {
return EqualsBuilder.reflectionEquals(this, o);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
For the time being, there are three major benefits.
For example, if you want a method that returns next year, you can implement it in the MyYear method. The logic is concentrated in one class, making it easy to change.
public MyYear nextYear() {
return new MyYear(this.year + 1);
}
It can be used as a key as follows.
import java.util.HashMap;
public final class Main {
public static void main(String[] args) {
var myMap = new HashMap<>();
myMap.put(MyYear.of(2018), "2018");
System.out.println(myMap.get(MyYear.of(2018))); // =>2018. equals()Null if there is no
}
}
You can compare objects normally. If you don't define equals (), you'll have to define a getter to get the value of the field.
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public final class MyYearTest {
@Test
public void testMyYearNext() {
MyYear now = MyYear.of(2018);
MyYear next = MyYear.of(2019);
assertThat(now.nextYear()).isEqualTo(next);
}
}
Object-oriented definitions often include "encapsulation," "inheritance," and "polymorphism." Aside from polymorphism, the other two don't quite fit.
Encapsulation is not a setter / getter, but I couldn't sort out what to write, whether inheritance is really necessary, and so on.
However, since I started to create Value Objects properly, I have less hesitation and can write code that is easy to understand. The only weakness is "it's a pain to write at first", but I think this is a necessary cost.
Actually, I think that Domain Driven Design may be easier to understand than Object Oriented, but I thought it was too outlandish, so I focused on Value Object for the time being.
If you want to do it more seriously (?), The following essay, which is also called "OO code training cast", will be helpful. However, this is pretty tough. I can't ... (ヽ ´ω`)
[^ 1]: Various additions have been made to the original text (ValueObject), but this time it is just a definition, so I will use the old description. [^ 2]: Even if final is added, it cannot be said that it is immutable if List etc. is included, but the explanation is omitted here. [java.time.Year]: https://docs.oracle.com/javase/jp/8/docs/api/java/time/Year.html
Recommended Posts