Hibernate JPA упрощает код для обновления (), удаления (), добавления()

#java #hibernate #jpa #refactoring

#java #гибернация #jpa #рефакторинг

Вопрос:

Я создал метод update (), который использует JPA. Это выглядит следующим образом:

 public boolean update(Programy program) throws Exception {
        try {
            entityManagerFactory = Persistence.createEntityManagerFactory("firebird_config_file");
            entityManager = entityManagerFactory.createEntityManager();

            entityManager.getTransaction().begin();
            entityManager.merge(program);
            entityManager.getTransaction().commit();

            entityManager.close();
            entityManagerFactory.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
  

В моем методе сохранения () и удаления я меняю только одну вещь — merge () -> persist() или delete(). Оставшаяся часть кода похожа на приведенную здесь. Как я могу реорганизовать этот код, чтобы упростить это?

Ответ №1:

Это очень хороший вариант использования шаблона, называемого методом шаблона.

Например, вы можете создать абстрактный класс, который оборачивает весь ваш шаблонный код в perform метод:

 abstract public class HibernateAction<T> {
    private EntityManagerFactory entityManagerFactory;
    //I'm passing EntityManagerFactory, because it should be singleton and you shouldn't
    //probably create it from scratch everytime
    public HibernateAction(EntityManagerFactory entityManagerFactory) {
        this.entityManagerFactory = entityManagerFactory;
    }

    protected abstract T action(EntityManager entityManager, T entity);

    public boolean perform(T entity) throws Exception {
        try {
            var entityManager = entityManagerFactory.createEntityManager();
            entityManager.getTransaction().begin();
            action(entityManager, entity); //call to action which need to be overriden
            entityManager.getTransaction().commit();
            entityManager.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }   
    }
}
  

затем вы можете просто создать класс, который наследует HibernateAction :

 public class UpdateAction extends HibernateAction<Program> {

    public UpdateAction(EntityManagerFactory entityManagerFactory) {
        super(entityManagerFactory);
    }

    @Override
    protected Program action(EntityManager entityManager, Program entity) {
        return entityManager.merge(entity);
    }
}
  

и, наконец, вы можете использовать его следующим образом:

 public boolean update(Program program) throws Exception {
    return updateAction.perform(program);
}
  

Но поскольку анонимные методы поддерживаются в Java (начиная с Java 8), вы также могли бы переписать его немного менее подробным способом, используя функции более высокого порядка:

 public class HibernateAction2{ // no longer abstract

    private EntityManagerFactory entityManagerFactory;

    public HibernateAction2(EntityManagerFactory entityManagerFactory) {
        this.entityManagerFactory = entityManagerFactory;
    }

    //we expect a user to pass lambda function, which would tell us what to do with an entity manager
    public boolean perform (Consumer<EntityManager> action) throws Exception {
        try {
            var entityManager = entityManagerFactory.createEntityManager();
            entityManager.getTransaction().begin();
            action.accept(entityManager);
            entityManager.getTransaction().commit();
            entityManager.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
  

и тогда вы можете использовать его как:

 hibernateAction2.perform(em -> em.merge(program)); //for merge

hibernateAction2.perform(em -> em.persist(program)); //for persist, etc.
  

Это называется шаблоном заимствования или шаблоном заимствования (или скобкой на языках FP), потому что вы «заимствуете» диспетчер объектов из hibernateAction2, чтобы использовать его для выполнения какого-либо действия, но он обрабатывает все другие вещи, такие как создание объекта или закрытие соединения.