Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 如何处理数百种数据类型的通用功能?(CRUD应用程序有200个非常相似的实体,没有继承)_Kotlin - Fatal编程技术网

Kotlin 如何处理数百种数据类型的通用功能?(CRUD应用程序有200个非常相似的实体,没有继承)

Kotlin 如何处理数百种数据类型的通用功能?(CRUD应用程序有200个非常相似的实体,没有继承),kotlin,Kotlin,我正在从事一个项目(基本上是一个CRUD应用程序),它有200多个数据库实体,其中每一个都有一些公共属性(id,name…)和许多其他属性以及对其他实体的引用。有些是大多数实体所共有的,有些则不是。(例如:var status:status?存在于每个实体中,状态本身除外。) 我不对实体使用继承,因为我需要多重继承来共享这些属性 为了加载这些实体,我有200多个DAO类(每个类对应于每个实体) 然后我还有200多个DTO课程 实体中几乎没有逻辑(基于其他属性验证和自动填充某些属性,例如fullN

我正在从事一个项目(基本上是一个CRUD应用程序),它有200多个数据库实体,其中每一个都有一些公共属性(
id
name
…)和许多其他属性以及对其他实体的引用。有些是大多数实体所共有的,有些则不是。(例如:
var status:status?
存在于每个实体中,状态本身除外。)

我不对实体使用继承,因为我需要多重继承来共享这些属性

为了加载这些实体,我有200多个DAO类(每个类对应于每个实体)

然后我还有200多个DTO课程

实体中几乎没有逻辑(基于其他属性验证和自动填充某些属性,例如fullName=firstName+lastName)。 DTO是普通对象

实体和DTO无权访问数据库

然后我有200多个映射器-将实体转换为DTO并返回。 此转换特定于每个实体-DTO的属性比实体多,映射器从实体本身+数据库填充它。 我需要从mapper调用其他映射器,因为每个实体都有大量属性,这些属性是对其他实体的引用,我要求这些子实体在API响应中可见

因为这些属性中有许多是公共的——我不使用继承——这导致了极其重复和大型的映射器,其中基本上有一半包含所有其他属性

然后我有200多个web控制器,它们通过common CrudController共享公共操作。 但是由于类型系统的限制,我必须在子控制器中实现一些方法。 例如:
CrudController
具有
schema()
方法,该方法调用
generator.generateJsonSchema(T::class.java)
。由于类型擦除,我不能直接使用T,所以我必须实现200+
schema
方法

这基本上适用于项目中的所有内容。 导出、导入和报告类也是如此——同样,每种类型都有200多个

因此,基本上对于每个应用程序功能,我需要200多个实现,因为类型不同,即使它们共享许多公共属性

为了管理所有这些,我目前使用活动代码生成。由于这个原因,该项目大约有20万行Kotlin代码,其中95%是生成的

这有一个类型安全的好处,不需要在整个项目中使用哈希表,但也会导致5分钟+完整的编译时间

问题是:有没有更好的方法来处理这样一个功能很少但数据类型很多的项目,而不使用继承?

一种解决方法是使用
is
操作符-只实现一次功能,然后为每个实体使用一个大的
when()
语句。这可能会导致运行时错误,并且基本上会将代码从多个类移动到一个类中,使其长度增加200倍

另一种解决方案可能是定义许多接口,并在实体本身上定义方法,使它们有数千行之长。这违反了许多原则,主要是SRP。我也不想让实体知道数据库连接(它们会变成ActiveRecord)、DTO和其他事情。甚至作为参数

我的直觉让我相信,如果我手头有Haskell的TypeClass之类的东西,事情会简单得多。 也许我仍然需要为每个功能创建200多个实例,但是主控制代码是相同的

例如:

我将拥有一个
typeclass映射器ab
,并为每种类型实现
convert
功能。 我会有一个
typeclass映射器ab=>Insertable a
save a
函数,它可以自由调用
convert a
函数。(替代应用程序服务层的
save
方法,该方法当前将DTO转换为实体,验证它(通过验证器),保存它(通过DTO)并返回DTO)

这意味着1)我将不需要拥有做所有事情的巨型实体2)我将能够删除大量代码,这些代码现在只是因为一些限制而被复制,比如我无法从通用方法调用特定方法

fun保存(实体:状态){
有趣的保存(实体:某物){}
验证(实体:状态){}
趣味验证(实体:某物){}
//fun validate(entities:List){/*但是在kotlin中不能这样做,因为类型擦除,所以即使这样也会失败*/}
fun validateAndSave(实体:T){
验证(实体)//无法执行此操作,类型未知,必须使用接口并在实体/DTO本身中实现它们
保存(实体)//无法执行此操作^
}
据我所知,目前我唯一能做的就是实现同等功能:

  • 如果Kotlin允许我为它们之外的类实现接口(KEEP-87,基本上是Kotlin的TypeClass);目前不可能

  • 通过使用继承而非函数,这就是我目前所做的:

  • 接口验证程序{
    趣味验证(实体:T)
    }
    接口保护程序{
    趣味储蓄(实体:T)
    }
    //其中200个
    类SomethingValidator:Validator{
    重写验证(实体:某物){/*…*/}
    }
    //其中200个
    类SomethingSaver:Saver{
    覆盖保存(实体:某物){/*…*/}
    }
    //应用服务层
    接口CrudAppService{
    fun validateAndSave(实体:T)
    }
    //它们都有一个共同点
    抽象类AbstractCrudAppService(validator:validator,val saver:saver):CrudAppService{
    //为了克服类型擦除,我需要在每个孩子身上实现这一点
    趣味entityClass():KClass
    //万岁!共同分享