2014-09-23 69 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的示例。 我希望它有帮助!