将父方法映射到其他类的子类的擦除相同

时间:2019-05-18 01:29:50

标签: java oop design-patterns

我正在尝试重构DAO,以使其在我们的代码库中更有用。当前,我们有一个参数化AbstractDao,它采用三种类型:

  1. 数据库表
  2. 数据库pojo
  3. 2的不同映射pojo表示形式

所以最终看起来像这样:

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);

但我希望合同保持不变。

感谢您的帮助。期待讨论!

1 个答案:

答案 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;
        }

希望这会有所帮助。