0 votes
in Education by (1.7m points)
I created update() method which is using JPA. It looks like this:

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;

        }

    }

In my save() and delete method I am changing only one thing - merge() -> persist() or delete(). Remaining part of code is similar as here. How can i refactor this code to simplify this?

JavaScript questions and answers, JavaScript questions pdf, JavaScript question bank, JavaScript questions and answers pdf, mcq on JavaScript pdf, JavaScript questions and solutions, JavaScript mcq Test , Interview JavaScript questions, JavaScript Questions for Interview, JavaScript MCQ (Multiple Choice Questions)

1 Answer

0 votes
by (1.7m points)
This is a very good use-case for a pattern called template method.

For example, you can create an abstract class, which wraps all your boilerplate code in perform method:

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;

        }   

    }

}

then you can just create a class which inherits 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);

    }

}

and finally you can use it like this:

public boolean update(Program program) throws Exception {

    return updateAction.perform(program);

}

But since anonymous methods are supported in Java (since Java 8), you could also rewrite it in a little bit less verbose way using higher order functions:

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;

        }

    }

}

and then you can use it like:

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

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

This is called loan pattern or loaner pattern (or bracket in FP languages), because you "loan" entity manager from hibernateAction2 to use it to do some kind of action, but it handles all other things, like creating an object or closing connection.
...