如果“干净”的意思是上层不知道下层的实现,你通常可以应用Tell,不要问原则。对于 CSV 流式处理示例,它类似于以下内容:
// This is a "global" API (meaning it is visible to all layers). This is ok as
// it is a specification and not an implementation.
public interface FooWriter {
void write(Foo foo);
}
// DAO layer
public class FooDaoImpl {
...
public void streamBigQueryTo(FooWriter fooWriter, ...) {
...
for (Foo foo: executeQueryThatReturnsLotsOfFoos(...)) {
fooWriter.write(foo);
evict(foo);
}
}
...
}
// UI layer
public class FooUI {
...
public void dumpCsv(...) {
...
fooBusiness.streamBigQueryTo(new CsvFooWriter(request.getOutputStream()), ...);
...
}
}
// Business layer
public class FooBusinessImpl {
...
public void streamBigQueryTo(FooWriter fooWriter, ...) {
...
if (user.canQueryFoos()) {
beginTransaction();
fooDao.streamBigQueryTo(fooWriter, ...);
auditAccess(...);
endTransaction();
}
...
}
}
通过这种方式,您可以自由地处理特定的ORM。这种“回调”方法的缺点是:如果您的层位于不同的JVM上,那么它可能不是很可行(在本例中,您需要能够序列化)。CsvFooWriter
关于通用DAO:我从未觉得有必要,我发现的大多数对象访问模式都不同到足以使特定的实现变得可取。但是,当然,进行层分离和强制业务层创建Hibernate标准是矛盾的路径。我会在DAO层中为每个不同的查询指定不同的查询方法,然后我会让DAO实现以它可能选择的任何方式(条件,查询语言,原始SQL等)获取结果。因此,而不是:
public class FooDaoImpl extends AbstractDao<Foo> {
...
public Collection<Foo> getByCriteria(Criteria criteria) {
...
}
}
public class FooBusinessImpl {
...
public void doSomethingWithFoosBetween(Date from, Date to) {
...
Criteria criteria = ...;
// Build your criteria to get only foos between from and to
Collection<Foo> foos = fooDaoImpl.getByCriteria(criteria);
...
}
public void doSomethingWithActiveFoos() {
...
Criteria criteria = ...;
// Build your criteria to filter out passive foos
Collection<Foo> foos = fooDaoImpl.getByCriteria(criteria);
...
}
...
}
我会做的:
public class FooDaoImpl {
...
public Collection<Foo> getFoosBetween(Date from ,Date to) {
// build and execute query according to from and to
}
public Collection<Foo> getActiveFoos() {
// build and execute query to get active foos
}
}
public class FooBusinessImpl {
...
public void doSomethingWithFoosBetween(Date from, Date to) {
...
Collection<Foo> foos = fooDaoImpl.getFoosBetween(from, to);
...
}
public void doSomethingWithActiveFoos() {
...
Collection<Foo> foos = fooDaoImpl.getActiveFoos();
...
}
...
}
虽然有人可能会认为我正在将一些业务逻辑向下推到DAO层,但对我来说,这似乎是一个更好的方法:将ORM实现更改为替代方法会更容易。想象一下,例如,出于性能原因,您需要使用原始JDBC读取s来访问某些特定于供应商的扩展:使用通用DAO方法,您需要更改业务层和DAO层。使用这种方法,您只需重新实现 DAO 层即可。Foo