Java 如何避免一个类的所有方法都通用的重复代码?

Java 如何避免一个类的所有方法都通用的重复代码?,java,dao,duplicate-removal,Java,Dao,Duplicate Removal,在我们的应用程序中,在DAO层中,每个方法都遵循几乎相同的顺序: public List getSomeValue(String[] parameters) { try { //Get connection from pool //Execute procedure //Process resultset } catch (SomeException e) { //Error handling mechanism

在我们的应用程序中,在DAO层中,每个方法都遵循几乎相同的顺序:

public List getSomeValue(String[] parameters) {
    try {
        //Get connection from pool
        //Execute procedure
        //Process resultset
    } catch (SomeException e) {
        //Error handling mechanism
    } finally {
        //Release connection
    }

    return someResult;  
}
上面代码中的所有注释行都描述了我们正在执行的操作

现在,除了过程-结果集部分,所有内容几乎完全相同

我的问题是,我们能否实现某种设计,这样我们就不必在每个方法中反复编写相同的代码?所以,我们只需要编写结果集处理部分

实用方法已经到位。但同样,我们必须在每个过程中以完全相同的顺序调用它们。我们能不能让这些预定义的方法被自动调用,我们只需要编写不同的部分?我甚至不确定这是否可能


注意:我们不能使用任何像Hibernate这样的ORM工具。

您可以创建一个基类,在那里编写通用方法,然后从基类继承类,这样每个子类都会继承它们


如果没有选择拥有一个超类(受框架或其他一些原因的限制),那么可以编写一个实用程序类,该类具有用于公共功能的静态方法

为什么不传入一个
映射器
,它知道如何将
结果集
转换为所需的元素列表。例如:

public List<T> getSomeValue(String[] parameters, ResultSetMapper<T> mapper) {
    try {
        //Get connection from pool
        //Execute procedure
        //Process resultset
        return mapper.convert(resultSet);  
    } catch (SomeException e) {
        //Error handling mechanism
    } finally {
        //Release connection
    }
}

interface RowMapper<T> {
    List<T> convert(ResultSet resultSet);
}
public List getSomeValue(字符串[]参数,结果映射器){
试一试{
//从池中获取连接
//执行程序
//过程结果集
返回mapper.convert(resultSet);
}捕获(某些例外){
//错误处理机制
}最后{
//释放连接
}
}
接口行映射器{
列表转换(ResultSet ResultSet);
}
您将传入不同的
mapper
实现,而
getSomeValue
方法将保持不变,因此您只需要它的一个实现


如果您在项目中使用Spring,您可以使用它的
ResultSetTextRactor
RowMapper
类来做类似的事情

Object doSomething(){
    return doInTransaction(trans -> {
        return trans.load();
    });
}
其中
InTrans

public interface InTrans<T> {
    T call(Transaction transaction);
}

或者,您可以使用
Spring
中的声明性事务。这使用了
talex
在其回答中提出的相同原则,只是对于您正在寻找的内容,我相信您想要的是使用
ResultSet
作为输入的功能接口(或其他类似接口)

因此,基本上,所有连接的获取、过程执行、结果集的循环和异常处理都保留在一个方法中,不会重复。当调用该方法时,传入将处理每一行的代码

它看起来像这样:

public void callingCode() {
    List<String> someList = new ArrayList<>();
    performQuery(
            "SELECT * FROM ...",
            new String[]{"param1", "param2"},
            rs -> {
                try {
                    // process your row here.
                    someList.add(rs.getString("somecolumn"));
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            });
}

public void performQuery(String query, String[] parameters, Consumer<ResultSet> processRow) {
    try {
        //Get connection from pool
        //Execute procedure
        ResultSet rs = null; // pretend this comes from the procedure call.
        //Process resultset
        while (rs.next()) {
            processRow.accept(rs);
        }
    } catch (Exception e) {
        //Error handling mechanism
    } finally {
        //Release resources
    }
}
调整代码:

public void callingCode() {
    List<String> someList = new ArrayList<>();
    performQuery(
            "SELECT * FROM ...",
            new String[]{"param1", "param2"},
            rs -> {
                // process your row here.
                someList.add(rs.getString("somecolumn"));
            });
}

public void performQuery(String query, String[] parameters, ResultSetConsumer rsConsumer) {
    try {
        //Get connection from pool
        //Execute procedure
        ResultSet rs = null; // pretend this comes from the procedure call.
        //Process resultset
        while (rs.next()) {
            rsConsumer.processRow(rs);
        }
    } catch (Exception e) {
        //Error handling mechanism
    } finally {
        //Release resources
    }
}
public void callingCode(){
List someList=new ArrayList();
表演(
“从…中选择*,
新字符串[]{“param1”,“param2”},
rs->{
//在这里处理您的行。
add(rs.getString(“somecolumn”);
});
}
公共void性能查询(字符串查询、字符串[]参数、结果消费者rsConsumer){
试一试{
//从池中获取连接
//执行程序
ResultSet rs=null;//假设它来自过程调用。
//过程结果集
while(rs.next()){
rsConsumer.processRow(rs);
}
}捕获(例外e){
//错误处理机制
}最后{
//释放资源
}
}

我想到了可重用的方法或继承的超类方法,为什么不将重复的代码移到方法(可能在抽象父类中)上,比如:
Connection getConnectionFromPool()
void executeProcedure()
?这些方法已经存在了。但同样,我们必须在每个过程中以完全相同的顺序调用它们。我们能不能让这些预定义的方法被自动调用,我们只需要编写不同的部分?我甚至不确定这是否可能。如果我们有两个方法getSomeValue1(),getSomeValue2(),我们不需要复制东西吗?你说过这些方法做的事情完全一样,只是转换结果集。如果这是真的,您只需要1个实现的
getSomeValue
,并传入不同的映射程序。我会研究一下,然后再给您回复。谢谢
public interface ResultSetConsumer {
    void processRow(ResultSet rs) throws SQLException;
}
public void callingCode() {
    List<String> someList = new ArrayList<>();
    performQuery(
            "SELECT * FROM ...",
            new String[]{"param1", "param2"},
            rs -> {
                // process your row here.
                someList.add(rs.getString("somecolumn"));
            });
}

public void performQuery(String query, String[] parameters, ResultSetConsumer rsConsumer) {
    try {
        //Get connection from pool
        //Execute procedure
        ResultSet rs = null; // pretend this comes from the procedure call.
        //Process resultset
        while (rs.next()) {
            rsConsumer.processRow(rs);
        }
    } catch (Exception e) {
        //Error handling mechanism
    } finally {
        //Release resources
    }
}