值类型Java库包AutoValue

Google发布了值类型Java的开源库包AutoValue 1.0。方便使用Java创建值类型。

什么是值类型value type?
一个值类型对象value-typed object是指没有标识的对象(注:类似DDD中的值对象),两个值对象只有在它们内部状态等同是才被认为等同,值对象是典型的不可变。

使用Java编写一个值类型非常单调,为了帮助开发人员实现DRY原则,google提供了AutoValue库包能够产生值对象源码,你所要做的就是定义一个值类型抽象规格,AutVlue将完成剩余的事情,产生你规格的具体实现类,这个实现包含值对象的各种属性:hascode, equals, toString的实现,一个构造器能够检查前置条件,所有的必要的getter方法,因为值对象是不可变的,所以没有setter方法。

AutoValue 是作为一个代码生成器,定义好你 的值类型规格后,一个注解处理器会在编译时创建完整的值类型实现类。需要加入项目的编译:


<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>

下面是一个复杂数字的值类型规格(抽象类):


import com.google.auto.value.AutoValue;

@AutoValue
public abstract class Complex {

public static Complex createFromCartesian(double real, double imaginary) {
return new AutoValue_Complex(real, imaginary);
}

public static Complex createFromPolar(double r, double theta) {
return new AutoValue_Complex(r * Math.cos(theta), r * Math.sin(theta));
}

public abstract double getReal();
public abstract double getImaginary();
}

注意到@AutoValue元注释,其中定义了抽象的getter方法,为了创建值类型实例,我们定义了一个或更多静态工厂方法,这里提供了两个工厂方法,工厂方法返回的是我们自己的抽象类,

当这个类第一次编译AutoValue库包创建下面的实现:



import javax.annotation.Generated;

@Generated("com.google.auto.value.processor.AutoValueProcessor")
final class AutoValue_Complex extends Complex {

private final double real;
private final double imaginary;

AutoValue_Complex(
double real,
double imaginary) {
this.real = real;
this.imaginary = imaginary;
}

@Override
public double getReal() {
return real;
}

@Override
public double getImaginary() {
return imaginary;
}

@Override
public String toString() {
return
"Complex{"
+
"real=" + real + ", "
+
"imaginary=" + imaginary
+
"}";
}

@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof Complex) {
Complex that = (Complex) o;
return (Double.doubleToLongBits(this.real) == Double.doubleToLongBits(that.getReal()))
&& (Double.doubleToLongBits(this.imaginary) == Double.doubleToLongBits(that.getImaginary()));
}
return false;
}

@Override
public int hashCode() {
int h = 1;
h *= 1000003;
h ^= (Double.doubleToLongBits(real) >>> 32) ^ Double.doubleToLongBits(real);
h *= 1000003;
h ^= (Double.doubleToLongBits(imaginary) >>> 32) ^ Double.doubleToLongBits(imaginary);
return h;
}
}

可见如果你自己编写,需要很多单调的代码。

值得注意的是,第一次编译会有编译错误,因为在工厂方法中引用了AutoValue_Complex ,它第一次不存在,以后再次编译就没有问题了。