Java 对将父方法映射到不同类的子类执行相同的擦除
我试图重构DAO,使其在我们的代码库中更可用。我们目前有一个参数化的AbstractDao,它有三种类型:Java 对将父方法映射到不同类的子类执行相同的擦除,java,algorithm,generics,design-patterns,collections,Java,Algorithm,Generics,Design Patterns,Collections,我试图重构DAO,使其在我们的代码库中更可用。我们目前有一个参数化的AbstractDao,它有三种类型: 数据库表 数据库pojo 2)的不同映射pojo表示形式 所以它最终看起来像: public class AbstractDao<T extends DatabaseTable, R extends DatabaseRecord, M> { public AbstractDao(Connection connection, Mapper<R,M> mapper)
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{
公共抽象DAO(连接,映射器映射器){
//将连接和映射程序保存到受保护的变量
}
公共列表插入(列表记录){
connection.insertBulk(
StreamEx.of(records).map(mapper::map).toList()
);
}
}
然而,在经典的DAO案例中,我们只处理pojo和表,这不起作用
然而,这里有一个通用的功能,可以抽象为一个更基本的抽象DAO,它在各个项目中都很有用。比如:
AbstractDao<T extends DatabaseTable, R extends Record>
insertMapped(List<M> mapped);
AbstractDao
它有一个子类
AbstractMappedDao<T extends DatabaseTable, R extends Record, M> extends AbstractDao<T, R>
AbstractMappedDao扩展了AbstractDao
摘要的方法如下:
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());
}
公共列表插入(列表记录){
super.insert(streamx.of(records).map(mapper::map.toList());
}
然而,这会产生一个“相同的擦除”问题,因为insert包含一个泛型列表
我尝试将其抽象为一个接口:
public interface Dao<T> {
public List<T> insert(List<T> records);
}
公共接口Dao{
公共列表插入(列表记录);
}
使抽象的实现Dao和映射的实现Dao,但同样的问题
所以我的问题是如何最好地解决这个问题?如果我将map的签名更改为以下内容,这将按预期工作:
AbstractDao<T extends DatabaseTable, R extends Record>
insertMapped(List<M> mapped);
insertMapped(列表映射);
但我宁愿保持合同不变
谢谢你的帮助。期待讨论 当涉及到组合行为时,最好要么使用组合,要么使用继承,这实际上就是你的情况。mapper
不会增加Dao
中已经存在的行为,而是在其中添加了一层额外的间接行为;这不一定是Dao
所关心的问题,比如
因此,我的建议是创建一个AbstractDao
类,该类能够组合mapper
(您可以根据需要只创建一个;但是通过组合,可以很容易地允许单个Dao
对象支持多个映射器):
这是更干净、更健壮和更可扩展的,因为您的insert
可以通过组合关注点以集中的方式处理各种关注点。完整的编译代码如下所示:
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;
}
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) {}
}
import java.util.List;
导入java.util.Map;
导入java.util.function.function;
导入java.util.stream.collector;
公共类删除{
公共抽象类AbstractDao{
专用连接;
私有映射器=新HashMap();
public void registerMapper(类映射类、函数映射器){
put(mappingClass,mapper);
}
公共列表插入(列表记录){
if(records.isEmpty())返回记录;
M rec=records.get(0);
太棒了。谢谢你的详细解释。我想这正是我想要的。整个“继承之上的沉着”设计原则是我期待阅读的一个原则。它明确地为我指明了正确的方向!在这里,当你将lambdas作为参数传递时,你会做出这样的行为。尽管传递lambdas时,你需要注意它的一些细微差别,如我在下面的回答中描述的: