我正在尝试重构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);
}
然后使Abstract实现Dao和Mapped实现Dao,但是同样,这也是一个问题。
所以我的问题是如何最好地解决这个问题?如果我将地图的签名更改为类似的内容,则可以按预期工作:
insertMapped(List<M> mapped);
但我希望合同保持不变。
感谢您的帮助。期待讨论!
答案 0 :(得分:1)
当涉及到组成行为时,总是最好使用组合而不是继承,这实际上是您的情况。 import JavaScriptCore
let javascript = """
var fetchPet = function(name) {
return new Pet(name);
};
"""
@objc protocol PetProtocol: JSExport {
var name: String {get set}
init(name: String)
}
class Pet: NSObject, PetProtocol {
var name: String
required init(name: String) {
self.name = name
}
}
let context = JSContext()!
context.setObject(Pet.self, forKeyedSubscript: "Pet" as NSString) //<-
context.evaluateScript(javascript)
let fcn = context.objectForKeyedSubscript("fetchPet")!
let petValue = fcn.call(withArguments: ["Fido"])
print("petValue.name is \(petValue?.forProperty("name")?.toString() ?? "???")")
if let petObj = petValue?.toObjectOf(Pet.self) as? Pet {
print("pet.name is \(petObj.name)")
}
else {
print("pet is nil :(")
}
与您的mapper
中已经没有的 augment 行为一样,与 adds 行为一样多,这是其中的间接层。像aspect/cross cutting concern一样,Dao
不一定是问题。
因此,我的建议是创建一个具有Dao
组成能力的单个AbstractDao
类(您可以根据需要创建一个{; 1,但是很容易组成一个单个{{1 }}对象以支持多个映射器):
mappers
然后创建一个Dao
方法,该方法允许使用已注册的 private Map<Class, Function> mappers;
public <M> void registerMapper(Class<M> mappingClass, Function<M, R> mapper) {
mappers.put(mappingClass, mapper);
}
处理未扩展insert
的记录的预转换 ,就像这样:
Record
这更干净,更健壮和可扩展,因为可以使您的mappers
通过已组成的关注点以集中的方式满足各种关注点。完整的编译代码如下所示:
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;
}
希望这会有所帮助。