Kotlin 如何处理数百种数据类型的通用功能?(CRUD应用程序有200个非常相似的实体,没有继承)
我正在从事一个项目(基本上是一个CRUD应用程序),它有200多个数据库实体,其中每一个都有一些公共属性(Kotlin 如何处理数百种数据类型的通用功能?(CRUD应用程序有200个非常相似的实体,没有继承),kotlin,Kotlin,我正在从事一个项目(基本上是一个CRUD应用程序),它有200多个数据库实体,其中每一个都有一些公共属性(id,name…)和许多其他属性以及对其他实体的引用。有些是大多数实体所共有的,有些则不是。(例如:var status:status?存在于每个实体中,状态本身除外。) 我不对实体使用继承,因为我需要多重继承来共享这些属性 为了加载这些实体,我有200多个DAO类(每个类对应于每个实体) 然后我还有200多个DTO课程 实体中几乎没有逻辑(基于其他属性验证和自动填充某些属性,例如fullN
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本身中实现它们
保存(实体)//无法执行此操作^
}
据我所知,目前我唯一能做的就是实现同等功能:
接口验证程序{
趣味验证(实体:T)
}
接口保护程序{
趣味储蓄(实体:T)
}
//其中200个
类SomethingValidator:Validator{
重写验证(实体:某物){/*…*/}
}
//其中200个
类SomethingSaver:Saver{
覆盖保存(实体:某物){/*…*/}
}
//应用服务层
接口CrudAppService{
fun validateAndSave(实体:T)
}
//它们都有一个共同点
抽象类AbstractCrudAppService(validator:validator,val saver:saver):CrudAppService{
//为了克服类型擦除,我需要在每个孩子身上实现这一点
趣味entityClass():KClass
//万岁!共同分享