Подтвердить что ты не робот

Как вы можете использовать шаблон Builder для объектов с JPA

Я читал, что полезно использовать шаблон построителя, когда у вас есть класс с большим количеством параметров. Интересно, как вы можете реализовать объект с использованием шаблона-строителя. Было бы здорово, если бы вы могли предоставить пример кода.

4b9b3361

Ответ 1

Конечно, возможно, вам просто нужно предоставить (возможно, вложенный) 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();

Просто имейте в виду, что вы должны исключить автогенерируемые поля, такие как первичный ключ (в этом примере case id), если у вас есть.

Если вы хотите избавиться от кода "шаблона" для создания классов Builder для каждого Entity, я бы рекомендовал библиотеку удобства, что-то вроде lombok. Затем вы получите своих Строителей (и даже больше), просто аннотируя свои Entites, может быть, стоит немного дополнительной работы, чтобы исключить поля id.

Вы должны взглянуть на Проект Ломбок

Тем не менее, вот какой-то код для проверки этого Builder (реализованный с помощью Spring Boot and 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());
    }

}