我正在尝试重构一个DAO,以使它在我们的代码库中更加可用。我们目前有一个参数化的AbstractDao,它接受三种类型:
所以它看起来就像:
public class AbstractDao<T extends DatabaseTable, R extends DatabaseRecord, M> {
public AbstractDao(Connection connection, Mapper<R,M> mapper) {
//save connection and mapper to protected variables
}
public List<M> insert(List<M> records) {
connection.insertBulk(
StreamEx.of(records).map(mapper::map).toList()
);
}
}但是,这并不适用于经典的DAO案例,在这种情况下,我们只处理pojo和表。
但是,这里有一个通用的功能,可以抽象成一个更基本的AbstractDao,它在各个项目中都很有用。类似于:
AbstractDao<T extends DatabaseTable, R extends Record>它有一个子类
AbstractMappedDao<T extends DatabaseTable, R extends Record, M> extends AbstractDao<T, R>摘要有一个方法,如:
public List<R> insert(List<R> records) {
connection.insertBulk(records);
}映射的方法应该如下:
public List<M> insert(List<M> records) {
super.insert(StreamEx.of(records).map(mapper::map).toList());
}但是,这会产生“相同的擦除”问题,因为insert接受泛型列表。
我尝试将它抽象到一个接口中:
public interface Dao<T> {
public List<T> insert(List<T> records);
}并且使抽象实现了Dao和映射实现了Dao,但是同样的问题。
所以我的问题是如何最好地解决这个问题?如果我将地图的签名更改为如下所示,则此操作与预期的相同:
insertMapped(List<M> mapped);但我宁愿保持合同不变。
谢谢你的帮助。期待着大家的讨论!
发布于 2019-05-18 03:16:49
当涉及到组合行为时,最好是使用组合而不是继承,这实际上就是您的情况。mapper并没有增加Dao中已经存在的行为,而是添加了行为,这是一个额外的间接层;这不一定是Dao所关心的,就像https://en.wikipedia.org/wiki/Aspect-oriented_programming一样。
因此,我的建议是创建一个AbstractDao类,该类具有组合mappers的能力(您可以根据自己的需要创建一个;但是使用组合可以很容易地允许单个Dao对象支持多个映射器):
private Map<Class, Function> mappers;
public <M> void registerMapper(Class<M> mappingClass, Function<M, R> mapper) {
mappers.put(mappingClass, mapper);
}然后创建一个insert方法,该方法允许使用它注册的mappers处理未扩展Record的记录的预转换,如下所示:
public <M> List<M> insert(List<M> records) {
if (records.isEmpty()) return records;
M rec = records.get(0);
List<? extends Record> actualRecords = (rec instanceof Record) ?
(List<Record>)records : createMappedRecords(records, rec.getClass());
connection.insertBulk(actualRecords);
return records;
}这是更干净、更健壮和更可扩展的,因为您的insert可以使用组合的关注点集中处理各种关注点。完整的编译代码如下所示:
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ParentErasure {
public abstract class AbstractDao<T extends DatabaseTable, R extends Record> {
private Connection connection;
private Map<Class, Function> mappers = new HashMap<>();
public <M> void registerMapper(Class<M> mappingClass, Function<M, R> mapper) {
mappers.put(mappingClass, mapper);
}
public <M> List<M> insert(List<M> records) {
if (records.isEmpty()) return records;
M rec = records.get(0);
List<? extends Record> actualRecords = (rec instanceof Record) ?
(List<Record>)records : createMappedRecords(records, rec.getClass());
connection.insertBulk(actualRecords);
return records;
}
private <M> List<R> createMappedRecords(List<M> records, Class<? extends Object> recordsClazz) {
Function<M, R> mapper = mappers.get(recordsClazz);
return records.stream()
.map(mapper::apply)
.collect(Collectors.toList());
}
}
public interface Dao<T> {
public List<T> insert(List<T> records);
}
}
class Record {}
class DatabaseTable {}
class DatabaseRecord {}
class Connection {
public void insertBulk(List<? extends Record> records) {}
}希望这能有所帮助。
https://stackoverflow.com/questions/56195282
复制相似问题