避免重复相同的逻辑
Avoid repetition of same logic
我有以下数据类:
sealed class ExampleDto
object Type1ExampleDto : ExampleDto()
object Type2ExampleDto : ExampleDto()
data class Type3ExampleDto(val name: Int, val age: Int) : ExampleDto()
data class Type4ExampleDto(val name: Int, val age: Int) : ExampleDto()
data class Type5ExampleDto(val email: String) : ExampleDto()
data class Type6ExampleDto(val name: Int, val age: Int, val email: String) : ExampleDto()
特别是,Type3ExampleDto
、Type4ExampleDto
和 Type6ExampleDto
共享一些公共字段,但区分 类型 对我的业务逻辑很重要(即,即使 Type3ExampleDto
和 Type4ExampleDto
相同,我也必须知道我是在 type3 还是 type4案例)。
在我的一种方法中,我有以下调用:
when (type) {
is Type3ExampleDto -> myMethod(type.vote, type.text)
is Type4ExampleDto -> myMethod(type.vote, type.text)
is Type6ExampleDto -> myMethod(type.vote, type.text)
else -> null
}
我发现我在所有 3 种情况下都执行相同的操作并重复同一行,这非常丑陋...
使Type3ExampleDto
、Type4ExampleDto
和Type6ExampleDto
成为某种接口的实现是有意义的,因为在这一点上只有我在做这种丑陋的重复?
如果三个dto都实现了下面的接口
interface MyInterface{
fun getVote() : Int
fun getText() : String
}
我会写:
if (type is MyInterface) {
myMethod(type.getVote(), type.getText())
}
所以,创建这个接口只是为了解决这个孤立的重复是可以接受的吗?
谢谢
请注意,您可以像这样更干净地完成它:
interface NameAndAgeDto {
val name: Int
val age: Int
}
data class Type3ExampleDto(override val name: Int, override val age: Int) : ExampleDto(), NameAndAgeDto
if (type is NameAndAgeDto) {
myMethod(type.name, type.age)
}
是否"acceptable"见仁见智。我觉得不错。
您可以更改您的模型,使您的逻辑基于行为而不是继承。
这种建模方式基于(但不完全是) 策略设计模式。
的原则
interface HasName {
val name: String
}
interface HasAge {
val age: Int
}
interface HasEmail {
val email: String
}
object Type1
object Type2
data class Type3(
override val name: String,
override val age: Int
) : HasName, HasAge
data class Type4(
override val name: String,
override val age: Int
) : HasName, HasAge
data class Type5(
override val email: String
) : HasEmail
data class Type6(
override val name: String,
override val age: Int,
override val email: String
) : HasName, HasAge, HasEmail
// Then you can pass any object to it.
fun main(obj: Any) {
// Koltin type-casts it nicely to both interfaces.
if (obj is HasName && obj is HasAge) {
myMethod(text = obj.name, vote = obj.age)
}
}
fun myMethod(vote: Int, text: String) {
}
如果你仍然希望所有类型都属于某个父类型,你可以使用标记接口(没有任何方法)。
interface DTO
interface HasName {
val name: String
}
interface HasAge {
val age: Int
}
interface HasEmail {
val email: String
}
object Type1 : DTO
object Type2 : DTO
data class Type3(
override val name: String,
override val age: Int
) : HasName, HasAge, DTO
data class Type4(
override val name: String,
override val age: Int
) : HasName, HasAge, DTO
data class Type5(
override val email: String
) : HasEmail, DTO
data class Type6(
override val name: String,
override val age: Int,
override val email: String
) : HasName, HasAge, HasEmail, DTO
// Here, it is DTO instead of Any
fun main(obj: DTO) {
if (obj is HasName && obj is HasAge) {
myMethod(text = obj.name, vote = obj.age)
}
}
并使用 sealed
class 而不是标记 interface
如果你需要 class 作为枚举 .
在这种情况下,when
over sealed class
是详尽无遗的所有选项,没有 null ->
.
我有以下数据类:
sealed class ExampleDto
object Type1ExampleDto : ExampleDto()
object Type2ExampleDto : ExampleDto()
data class Type3ExampleDto(val name: Int, val age: Int) : ExampleDto()
data class Type4ExampleDto(val name: Int, val age: Int) : ExampleDto()
data class Type5ExampleDto(val email: String) : ExampleDto()
data class Type6ExampleDto(val name: Int, val age: Int, val email: String) : ExampleDto()
特别是,Type3ExampleDto
、Type4ExampleDto
和 Type6ExampleDto
共享一些公共字段,但区分 类型 对我的业务逻辑很重要(即,即使 Type3ExampleDto
和 Type4ExampleDto
相同,我也必须知道我是在 type3 还是 type4案例)。
在我的一种方法中,我有以下调用:
when (type) {
is Type3ExampleDto -> myMethod(type.vote, type.text)
is Type4ExampleDto -> myMethod(type.vote, type.text)
is Type6ExampleDto -> myMethod(type.vote, type.text)
else -> null
}
我发现我在所有 3 种情况下都执行相同的操作并重复同一行,这非常丑陋...
使Type3ExampleDto
、Type4ExampleDto
和Type6ExampleDto
成为某种接口的实现是有意义的,因为在这一点上只有我在做这种丑陋的重复?
如果三个dto都实现了下面的接口
interface MyInterface{
fun getVote() : Int
fun getText() : String
}
我会写:
if (type is MyInterface) {
myMethod(type.getVote(), type.getText())
}
所以,创建这个接口只是为了解决这个孤立的重复是可以接受的吗?
谢谢
请注意,您可以像这样更干净地完成它:
interface NameAndAgeDto {
val name: Int
val age: Int
}
data class Type3ExampleDto(override val name: Int, override val age: Int) : ExampleDto(), NameAndAgeDto
if (type is NameAndAgeDto) {
myMethod(type.name, type.age)
}
是否"acceptable"见仁见智。我觉得不错。
您可以更改您的模型,使您的逻辑基于行为而不是继承。
这种建模方式基于(但不完全是) 策略设计模式。
interface HasName {
val name: String
}
interface HasAge {
val age: Int
}
interface HasEmail {
val email: String
}
object Type1
object Type2
data class Type3(
override val name: String,
override val age: Int
) : HasName, HasAge
data class Type4(
override val name: String,
override val age: Int
) : HasName, HasAge
data class Type5(
override val email: String
) : HasEmail
data class Type6(
override val name: String,
override val age: Int,
override val email: String
) : HasName, HasAge, HasEmail
// Then you can pass any object to it.
fun main(obj: Any) {
// Koltin type-casts it nicely to both interfaces.
if (obj is HasName && obj is HasAge) {
myMethod(text = obj.name, vote = obj.age)
}
}
fun myMethod(vote: Int, text: String) {
}
如果你仍然希望所有类型都属于某个父类型,你可以使用标记接口(没有任何方法)。
interface DTO
interface HasName {
val name: String
}
interface HasAge {
val age: Int
}
interface HasEmail {
val email: String
}
object Type1 : DTO
object Type2 : DTO
data class Type3(
override val name: String,
override val age: Int
) : HasName, HasAge, DTO
data class Type4(
override val name: String,
override val age: Int
) : HasName, HasAge, DTO
data class Type5(
override val email: String
) : HasEmail, DTO
data class Type6(
override val name: String,
override val age: Int,
override val email: String
) : HasName, HasAge, HasEmail, DTO
// Here, it is DTO instead of Any
fun main(obj: DTO) {
if (obj is HasName && obj is HasAge) {
myMethod(text = obj.name, vote = obj.age)
}
}
并使用 sealed
class 而不是标记 interface
如果你需要 class 作为枚举 .
在这种情况下,when
over sealed class
是详尽无遗的所有选项,没有 null ->
.