在我们的应用程序中,在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工具。
答案 0 :(得分:1)
为什么不传入知道如何将mapper
转换为您期望的元素列表的ResultSet
。例如:
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);
}
您传递了不同的mapper
实现,而getSomeValue
方法将保持不变,因此您只需要实现一次。
如果您在项目中使用Spring,则可以使用其ResultSetExtractor
或RowMapper
类来执行类似操作。
答案 1 :(得分:1)
从java 8开始,你可以将方法重构为类似的东西;
Object doSomething(){
return doInTransaction(trans -> {
return trans.load();
});
}
InTrans
public interface InTrans<T> {
T call(Transaction transaction);
}
和doInTransaction
<T> T doInTransaction(InTrans<T> callable){
try {
Connection connection = ...
return callable.call(connection));
} catch (SomeException e) {
//Error handling mechanism
} finally {
//Release connection
}
}
或者,您可以使用Spring
答案 2 :(得分:1)
这使用talex
在他的回答中提出的相同原则,除了对于你正在寻找的东西,我相信你想要的是使用Consumer<T>
功能界面(或其他类似的东西)接口)使用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
}
}
修改强>
Consumer<T>
功能接口令人烦恼的是方法签名不允许任何已检查的异常,因此需要明确处理SQLException
(在上面的代码中,你可以看到我被迫将SQLException
包裹在RuntimeException
中。为了避免这种烦恼,您可以选择不使用内置的Consumer<T>
功能界面,而是创建自己的包含throws SQLException
作为方法签名的一部分。
ResultSetConsumer
界面:
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
}
}
答案 3 :(得分:0)
您可以创建一个具有在其中编写的公共方法的基类,然后从基类继承该类,因此每个子类都将继承它们。
如果拥有超类不是一个选项(受框架或其他一些原因限制),您可以编写一个具有静态方法的实用程序类来实现常用功能。