值型別Java庫包AutoValue

banq發表於2015-01-15
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>
<p class="indent">


下面是一個複雜數字的值型別規格(抽象類):

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();
}
<p class="indent">

注意到@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;
  }
}
<p class="indent">


可見如果你自己編寫,需要很多單調的程式碼。

值得注意的是,第一次編譯會有編譯錯誤,因為在工廠方法中引用了AutoValue_Complex ,它第一次不存在,以後再次編譯就沒有問題了。

相關文章