2011-11-13 44 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

好的,但我想使用的主要原因一個建造者是這樣,我可以使領域「最終」。如果你使用現場訪問,你不能讓他們最終可以嗎? –

相關問題