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

Exceptions in java: how reduce repeated code

我在 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);
    }
}

好吧,我想让你看看关键部分。我用我拥有的每一种方法都重复了它。如果它是简单的代码,我可以创建一个方法,将所有代码放入其中并调用该方法,而不是重复代码。问题是它不是正常代码,它们是异常。

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

谢谢!

is there any solution to reuse code and not to repeat (copy-pasting) the code in every method?

有。

你的函数"meat"在这里

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

如果你仔细观察,你可能会发现这是一个接受 Session 作为参数的 "function",而 returns 是一个 User。然后你可以做的是让这个函数成为执行所有异常处理的东西的参数。

在 Java 中,这通常意味着将函数表示为 "object"

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 (...) {
        // ...
    }
}

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

看起来像是 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();
        }
    );
}