在Java中通常定義一個模型類時,需要定義一堆不同類型的成員變量,而且為了滿足面向對象的基本特征,又要定義一堆相應的Getter和Setter等方法,這個過程是非??菰锏囊獙懸欢褬影宕a。雖然現(xiàn)在 IDE 可以很好的幫我們生成這些樣板代碼,但是如果看到一個模型類里面有這么一堆的方法,總覺是會覺得不夠清晰。
我只想知道這個模型有哪些屬性,以及特殊的方法,并不想知道大家都有的東西,你卻非要讓我看。。。
好了,現(xiàn)在有辦法可以解決這個問題了,使用 Google 開源的 AutoValue 就可以解決上述煩惱,而且最近AutoValue項目支持了大家期待已久的Extension API,使得AutoValue更加靈活,至于這個Extension API是干啥的后面會講到,現(xiàn)在暫時不用去關心他。
普通的 Java 模型
我們這里舉個故事(Story)的例子,一個故事模型擁有一個id,以及一個title。下面我們來看下用Java代碼來表示該模型的寫法。
不太嚴謹?shù)膶懛?/h3>
我們先來看下一般情況下我們是怎么定義這個 POJO 的業(yè)務模型的。
public class Story{
public int id;
public String title;
}
上面的寫法非常簡單,不過有些情況下可能會有問題,比如對象比較時,而且也不符合封裝的要求,不過一般情況下業(yè)務邏輯簡單,還處在快速迭代的時候這樣寫也沒什么問題,而且重點是他 只有4行代碼!
比較規(guī)范的寫法
下面看下正常情況下的寫法:
public class Story{
private int id;
private String title;
public Story(int id, String title){
this.id = id;
this.title = title;
}
public int id(){
return this.id;
}
public int title(){
return this.title;
}
}
這樣寫符合了面向對象的基本特征封裝的要求,但是如果這個Story是在列表或者集合中有用到比較的時候,這么寫是有問題的,應該繼續(xù)覆蓋hashCode()和equals()方法,如果有特殊格式的輸出,還得覆蓋toString()方法。
把這些東西都補全的寫法如下:
public class Story{
private int id;
private String title;
public Story(int id, String title){
this.id = id;
this.title = title;
}
public int id(){
return this.id;
}
public int title(){
return this.title;
}
@Override
public String toString(){
return id + title;
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + this.id;
hash = 31 * hash + (null == title ? 0 : title.hashCode());
return hash;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof Stroy)) return false;
Story s = (Story) o;
if (s.id != s.id) return false;
return s.title.equals(s.title);
}
}
上面的版本是一個比較完整的模型寫法,相比起最初的版本,代碼多了不少從原來的4行變成了現(xiàn)在的39行!
OMG!現(xiàn)在的版本還沒有實現(xiàn)Parcelable接口,如果再在他的基礎上實現(xiàn)Parcelable接口,那代碼又得增加十幾行,想想都心累啊。
使用AutoValue拯救你的代碼
我本想要一個只有幾行的模型類,但是出于各方面原因,我得到了一個幾十行代碼的模型類,為了解決這個問題偉大的Google開發(fā)了AutoValue這個庫來自動生成這些樣板代碼,解放我們的雙手,讓我們把更多的精力放在更重要的事情上。
使用AutoValue
使用方法很簡單,只需要在你的項目中引入AutoValue的插件即可
dependencies {
apt 'com.google.auto.value:auto-value:1.2'
}
然后在代碼中使用@AutoValue注解來指定哪個類需要生成類似于上面的樣板代碼。下面我們使用AutoValue來重新實現(xiàn)一下Story模型。
@AutoValue
public abstract class Story{
public abstract int id();
public abstract String title();
}
使用@AutoValue注解后,AutoValue會生成一個AutoValue_你的類名為名稱的類,這個類是包級私有的,他里面有私有的成員變量,對應的構造函數(shù),以及重寫的hashCode()、equals()和toString()方法,而且這些方法都是被測試過的確保無誤的,你可以放心的使用。由于這個生成的子類是包級私有的,所以這里在給Story提供構造方法的時候需要提供一個靜態(tài)的構造方法,代碼如下:
@AutoValue
public abstract class Story{
public abstract int id();
public abstract String title();
public static Story create(int id, String title){
new AutoValue_Story(id,title);
}
}
好了,使用AutoValue后,這短短幾行代碼就完成了上面幾十行代碼干的事,而且這樣生成出來的代碼都是被測試過準確無誤的,這也避免了一些因為手誤或者邏輯錯誤導致的BUG的產(chǎn)生,是不是很爽?必須很爽??!
But... 我們要更爽一點!
AutoValue Extension API
大家注意到?jīng)]有上面使用AutoValue實現(xiàn)的Story模型并沒有實現(xiàn)Parcelable接口,那如果要實現(xiàn)這個接口是不是又得一堆代碼呢?當然不會,因為我們有Extension API,因為有了他我們可以使用基于他實現(xiàn)出來的AutoValue: Parcel Extension來實現(xiàn)Parcelable接口。
使用 Parcel Extension 實現(xiàn) Parcelable 接口
首先我們需要在項目中集成 AutoValue Parcel Extension
dependencies {
provided 'com.google.auto.value:auto-value:1.2'
apt 'com.google.auto.value:auto-value:1.2'
apt 'com.ryanharter.auto.value:auto-value-parcel:0.2.1'
}
然后再在代碼中加入implements Parcelable即可
@AutoValue
public abstract class Story implements Parcelable{
public abstract int id();
public abstract String title();
public static Story create(int id, String title){
new AutoValue_Story(id,title);
}
}
是不是已經(jīng)體會到了AutoValue Extension的厲害了?反正我是覺得碉堡了!
有了這個擴展功能,能干的事情就多了,常規(guī)的像對象序列化成 JSON 字符串,將 JSON 字符串解析成對象等這些事情就不用自己再去動手去寫了,直接用AutoValue生成就可以了,再也不用去寫那些toJson()和fromJson之類的方法了,真是爽歪歪啊!
更多的 AutoValue Extension
目前已經(jīng)有人實現(xiàn)了一些 AutoValue 的擴展了,具體的可以看這里。如果這些都無法滿足你的需求,那你可以使用 AutoValue Extension API去自己實現(xiàn)一個 AutoValue 的擴展。