Java中的异常:如何减少重复代码

时间:2018-12-18 21:49:41

标签: java hibernate exception-handling

我在Java中使用数据访问对象(DAO)模式,并且在我的文件中重复了相同的代码。事情是这样的:

public User getById(int id) throws BDException {
    Session session = sessionFactory.getCurrentSession();
    Transaction tx = session.getTransaction();

    try {
        tx.begin();
        Query query = session.createQuery("SELECT u FROM User u WHERE u.id=:id");
        query.setString("id", id);
        User user = (User) query.uniqueResult();
        tx.commit();

        return user;
    }
    catch(javax.validation.ConstraintViolationException | org.hibernate.exception.ConstraintViolationException cve) {
        try {
            if(tx.getStatus() == TransactionStatus.ACTIVE) {
                tx.rollback();
            }
        }
        catch(Exception exc) {
            LOGGER.error("Error rollback in method='" + getMethodName() + "'");
        }
        throw new BDException(cve);
    }
    catch(RuntimeException ex) {
        try {
            if(tx.getStatus() == TransactionStatus.ACTIVE) {
                tx.rollback();
            }
        }
        catch(Exception exc) {
            LOGGER.error("Error rollback in method='" + getMethodName() + "'");
        }
        throw ex;
    }
    catch(Exception ex) {
        try {
            if(tx.getStatus() == TransactionStatus.ACTIVE) {
                tx.rollback();
            }
        }
        catch(Exception exc) {
            LOGGER.error("Error rollback in method='" + getMethodName() + "'");
        }
        throw new RuntimeException(ex);
    }
}

好吧,我希望你看看渔获物的一部分。我用每种方法都重复过一次。如果这是简单的代码,我可以创建一个方法,将所有代码放入其中,然后调用该方法,而不必重复代码。问题在于它不是普通代码,它们是异常。

那么,有什么解决方案可以重用代码,而不必在每种方法中重复(粘贴)代码吗?

谢谢!

2 个答案:

答案 0 :(得分:4)

  

有什么解决方案可以重用代码,而不必在每个方法中重复(粘贴)代码?

有。

功能的“肉”在这里

    Query query = session.createQuery("SELECT u FROM User u WHERE u.id=:id");
    query.setString("id", id);
    User user = (User) query.uniqueResult();

如果您非常仔细地quin着眼睛,可能会看到这是一个接受Session作为参数并返回User的“函数”。然后,您可以做的就是将此函数作为执行所有异常处理的事物的参数。

在Java中,通常意味着将函数表示为“对象”

User MyCrazyFunctionThing::uniqueResult(Session session) {
    Query query = session.createQuery(this.sql);
    query.setString("id", this.id);
    return query.uniqueResult();
}

User DatabaseGateway::execute(MyCrazyFunctionThing q) {
    Session session = sessionFactory.getCurrentSession();
    Transaction tx = session.getTransaction();

    try {
        tx.begin();
        User user = q.uniqueResult(session)
        tx.commit();

        return user;
    } catch (...) {
        // ...
    }
}

马上,您可以将其转换为可以在您尝试从会话中获取唯一用户时运行的逻辑。

您可以使用泛型使它更加通用

interface MyCrazyGenericThing<T> {
    T uniqueResult(Session session);
}

class MyCrazyFunctionThing implements MyCrazyGenericThing<User> {
    User uniqueResult(Session session) {
        Query query = session.createQuery(this.sql);
        query.setString("id", this.id);
        return query.uniqueResult();
    }
}

<T> T DatabaseGateway::execute(MyCrazyGenericThing<T> q) {
    Session session = sessionFactory.getCurrentSession();
    Transaction tx = session.getTransaction();

    try {
        tx.begin();
        T result = q.uniqueResult(session)
        tx.commit();

        return result;
    } catch (...) {
        // ...
    }
}

您在这里看到的是策略模式,该策略模式用于指定在事务逻辑中应运行哪些代码。

答案 1 :(得分:2)

看起来像Execute Around idiom的工作。

将专用代码放在lambda表达式中。将专用代码传递给具有通用代码的方法,该方法将在适当的位置执行包含lambda表达式的对象。

对于您的代码,具体取决于您要排除的内容,用法可能类似于:

public User getById(int id) throws BDException {
    return query(
        "SELECT u FROM User u WHERE u.id=:id",
        query -> {
            query.setString("id", id);
            return (User) query.uniqueResult();
        }
    );
}