2011-11-13 31 views
12

我读到,当您有一个具有大量参数的类时,使用构建器模式很有用。我想知道如何使用构建器模式来实现一个实体。如果您可以提供示例代码,那将会很棒。如何使用构造模式用于具有JPA的实体

+2

为什么它很重要的类是实体?为什么使用构建器模式来构建任何不同的实体来使用它来构建其他任何东西? –

+0

我希望它是一个实体,以便能够将其存储在数据库中。 –

回答

5

当然,这是可能的,你只需要为每个实体提供一个(可能是嵌套的)Builder。

下面是一个工作示例:

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 

@Entity 
public class FluentEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 
    private String someName; 
    private int someNumber; 
    private boolean someFlag; 

    protected FluentEntity(){} 

    private FluentEntity(String someName, int someNumber, boolean someFlag) { 
     this.someName = someName; 
     this.someNumber = someNumber; 
     this.someFlag = someFlag; 
    } 

    public long getId() { 
     return id; 
    } 

    public String getSomeName() { 
     return someName; 
    } 

    public int getSomeNumber() { 
     return someNumber; 
    } 

    public boolean isSomeFlag() { 
     return someFlag; 
    } 

    public static FluentEntityBuilder builder() { 
     return new FluentEntityBuilder(); 
    } 

    public static class FluentEntityBuilder { 

     private String someName; 
     private int someNumber; 
     private boolean someFlag; 

     public FluentEntityBuilder setSomeName(final String someName) { 
      this.someName = someName; 
      return this; 
     } 

     public FluentEntityBuilder setSomeNumber(final int someNumber) { 
      this.someNumber = someNumber; 
      return this; 
     } 

     public FluentEntityBuilder setSomeFlag(final boolean someFlag) { 
      this.someFlag = someFlag; 
      return this; 
     } 

     public FluentEntity build() { 
      return new FluentEntity(someName, someNumber, someFlag); 
     } 

    } 

} 

使用它会是这样的代码:

FluentEntity entity = FluentEntity.builder().setSomeName(someName).setSomeNumber(someNumber) 
       .setSomeFlag(someFlag).build(); 

请记住,你必须排除像主键自动生成的字段(这个例子的案例是id)如果你有一些。

如果你想摆脱为每个实体创建Builder类的“样板”代码,我会推荐一个类似lombok的便利库。然后,您只需注释您的Entites即可获得Builders(甚至更多),也许需要额外的工作才能排除id字段。

你应该看看Project Lombok

尽管如此,这里是一些代码来测试这个生成器(与Spring引导和Hibernate实现)。

存储库:

import org.springframework.data.repository.CrudRepository; 

import com.example.model.FluentEntity; 

public interface FluentEntityRepository extends CrudRepository<FluentEntity, Long> { 

} 

这里有一些测试:

import static org.hamcrest.CoreMatchers.is; 
import static org.hamcrest.CoreMatchers.notNullValue; 
import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.greaterThan; 

import java.util.stream.StreamSupport; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.test.context.SpringBootTest; 
import org.springframework.test.context.junit4.SpringRunner; 
import org.springframework.transaction.annotation.Transactional; 

import com.example.model.FluentEntity; 

@RunWith(SpringRunner.class) 
@Transactional 
@SpringBootTest 
public class FluentEntityRepositoryTests { 

    @Autowired 
    private FluentEntityRepository fluentEntityRepository; 

    @Test 
    public void insertAndReceiveFluentEntityCreatedWithBuilder() { 
     final String someName = "name"; 
     final int someNumber = 1; 
     final boolean someFlag = true; 

     FluentEntity entity = FluentEntity.builder().setSomeName(someName).setSomeNumber(someNumber) 
       .setSomeFlag(someFlag).build(); 

     entity = fluentEntityRepository.save(entity); 
     assertThat("Entity did not get an generated Id!", entity.getId(), greaterThan(-1L)); 
     assertThat("Entity name did not match!", entity.getSomeName(), is(someName)); 
     assertThat("Entity number did not match!", entity.getSomeNumber(), is(someNumber)); 
     assertThat("Entity flag did not match!", entity.isSomeFlag(), is(someFlag)); 
    } 

    @Test 
    public void insertSomeAndReceiveFirst() { 
     fluentEntityRepository.save(FluentEntity.builder().setSomeName("A").setSomeNumber(1).setSomeFlag(true).build()); 
     fluentEntityRepository 
       .save(FluentEntity.builder().setSomeName("B").setSomeNumber(2).setSomeFlag(false).build()); 
     fluentEntityRepository.save(FluentEntity.builder().setSomeName("C").setSomeNumber(3).setSomeFlag(true).build()); 

     final Iterable<FluentEntity> findAll = fluentEntityRepository.findAll(); 
     assertThat("Should get some iterable!", findAll, notNullValue()); 

     final FluentEntity fluentEntity = StreamSupport.stream(findAll.spliterator(), false).findFirst().get(); 
     assertThat("Should get some entity!", fluentEntity, notNullValue()); 
    } 

} 
+0

JPA框架能够“自动”('@ Autowire')创建只有构建器中有setter的实体的实例吗? –

+1

我不知道我是否得到了您的问题,但通常情况下,如果使用字段访问,则不需要使用setter。然后,JPA提供程序不会调用setter,并且构建器可能足以满足您的业务代码。请参阅“2.2持久性字段和属性”:http://download.oracle.com/otn-pub/jcp/persistence-2_1-fr-eval-spec/JavaPersistence.pdf –

+0

好的,但我想使用的主要原因一个建造者是这样,我可以使领域“最终”。如果你使用现场访问,你不能让他们最终可以吗? –

相关问题