2014-09-23 70 views
6

我有幾種不同的POJOs,它們使用builder pattern,但是在爲每一個添加一個構建器並生成Object.toString,Object.hashCodeObject.equals後,我的類最終大約有100行代碼。必須有更好的方法來處理這個問題。我認爲有某種反光建築師會幫助很多,但我不確定這是否是一種好的做法,我也不確定我會如何實現。換句話說,有沒有一種方法來實現這樣的構建器?太多的樣板,我怎樣才能減少我的POJO建設者?

一個簡單的POJO:

public class Foo { 

    public int id; 
    public String title; 
    public boolean change; 
    ... 

} 

然後某種反射建設者:

Foo = ReflectiveBuilder.from(Foo.class).id(1).title("title").change(false).build(); 
+0

你是否使用Apache commons forString hashCode並等於?這仍然很痛苦,但會爲你節省很多時間。你的代碼有一個基礎類,它反射地做了toString,equals和hashCode然後從我的 – Leon 2014-09-23 07:18:10

+0

@Leon派生所有POJO,實際上。但是每個班級仍然最終會有70-100行代碼來自每個構建者。必須有一個更好的模式,我只是沒有意識到或者實現反射式生成器的方式,至少這是我的感受。 – buildpattern 2014-09-23 07:21:16

回答

4

簡短的回答沒有。你所要求的是不可能的。反射在運行時查看代碼並動態調用方法,它不能生成實際的方法。

你可以做什麼是:

Foo foo = ReflectiveBuilder.from(Foo.class). 
       set("id", 1). 
       set("title", "title"). 
       build(); 

這有三個大規模問題:

  1. 字段是String秒 - 一個錯字導致運行時錯誤而不是編譯時一個,
  2. 值爲Object s - 錯誤類型會導致運行時錯誤,而不是編譯時錯誤,並且
  3. 由於反射非常緩慢,所以它會比替代方法慢得多。

因此,雖然可能的基於反射的解決方案(請參閱Apache Commons BeanUtils BeanMap)並不實際。

很長的回答,如果你願意允許一些編譯時魔術,你可以使用Project Lombok。 Lombok背後的想法是使用Java註釋預處理器系統從註釋生成樣板代碼。

真正神奇的是,至少所有的IDE,至少大3,理解註釋預處理和代碼完成仍然會正常工作,即使代碼真的存在。

在一個POJOBuilder可以使用@Data的情況和@Builder

@Data 
@Builder 
public class Foo { 

    public int id; 
    public String title; 
    public boolean change; 
    ... 

} 

@Data註釋將產生:

  • 所需參數的構造函數(即通吃final字段),
  • equalshashCode使用所有字段的方法(可以與@EqualsAndHashCode註釋被配置)
  • 一個toString方法上的所有字段(可與@ToString註釋和
  • public getter和setter所有字段(可使用@Getter/@Setter註解字段被配置來配置)。

@Builder註釋會產生稱爲Builder可以使用Foo.builder()被實例化的內部類。

請確保您配置equalshashCodetoString方法,如果你有兩個班,龍目島有相互之間的引用,那麼你最終會在默認情況下,一個無限循環既是類包括其他的這些方法。

還有一個新的configuration system,使您可以使用,例如,流利的制定者,所以你可以更減配建築商做的路程,如果你的POJO是可變的:

new Foo().setId(3).setTitle("title)... 

對於另一種方法,您可以看看Aspect-oriented programming(AOP)和AspectJ。 AOP允許你將類切成「方面」,然後使用預編譯器使用某些規則將它們粘在一起。例如,您可以使用自定義註釋和一個方面來實現Lombok所做的。然而,這是一個相當先進的話題,而且可能是過度的。

+0

我意識到'Gson'實際上使用一種非常相似的方法來反序列化一個'Object',因爲它使用反射來初始化每個'Field'。基於相同反射實現的構建器可能不是一個壞主意。你怎麼看? – buildpattern 2014-09-23 10:29:38

+1

@buildpattern我指出這是一個可怕的想法。 GSON這樣做是因爲它已經到了。您會丟失編譯時類型安全性,這意味着您可以隨時遇到運行時錯誤,並且速度會下降。不要使用反射,除非你絕對**必須**,而不要**減少樣板。 – 2014-09-23 10:39:34

4

也許Project Lombok(是該網站是醜陋的)是一個選擇。 Lombok根據註釋將代碼注入到類中。

隨着龍目島使用@Data註釋生成的getter,setter方法,toString()hashCode()equals()

@Data 
public class Foo { 
    public int id; 
    public String title; 
    public boolean change; 
} 

看一看在@Data documentation section的例子來看看生成的代碼。

龍目島還提供了一個@Builder,爲您的班級生成一個建造者。但要知道,這是一個實驗性的功能:

@Builder 
public class Foo { 
    public int id; 
    public String title; 
    public boolean change; 
} 

現在你可以這樣做:

Foo foo = Foo.builder() 
    .id(123) 
    .title("some title") 
    .change(true) 
    .build(); 
0

我創建了一個小型庫CakeMold來完成POJO的流暢初始化。它使用反射,當然不是很快。但在需要編寫測試時可以非常有用。

Person person = CakeMold.of(Person.class) 
    .set("firstName", "Bob") 
    .set("lastName", "SquarePants") 
    .set("email", "[email protected]") 
    .set("age", 22) 
    .cook(); 
1

我個人使用this網站創建所有的POJO的對我的樣板代碼。所有你需要做的就是粘貼你想要解析的JSON,並且它會爲你生成所有的類。然後我使用Retrofit來完成信息的請求/緩存/解析。 Here是我的Github帳戶中的Retrofit和POJO的示例。 我希望它有幫助!