最近开发新项目时遇到一个问题,项目中对与许多资源的字段嵌套层级不少,可是字段又都从一个接口返回,而且存在与一个JSON对象中。带来的问题:安全
虽然使用kotlin,语法上已经能精简不少,可是这种需求不免让代码的可读性,维护性不好。服务器
对于用户资源的展现。首先资源类型分为:Image,Video,而后资源的类型分为normal,red,burning,redBurning,状态分为read,noRead。而服务器返回的相关字段都存储在一个JSON对象中,而且都属于同一级的属性。那么能够获得这样的一个data classide
data class ResBean(val url: String, val format: String, val type: String, val viewStatus: String){
companion object { // 在伴生对象中定义一些常量来表示其中的字段类型
const val RES_FORMAT_VIDEO = "video"
const val RES_FORMAT_IMAGE = "image"
const val RES_RORMAT_UNKONW = "unKnow"
const val RES_TYPE_NORMAL = "normal"
const val RES_TYPE_RED = "red"
const val RES_TYPE_RED_BURNING = "red_burning"
const val RES_TYPE_BURNING = "burning"
}
}
复制代码
使用时的需求场景,如今须要在一个ViewPager中展现这些资源,首先须要考虑到时Format,其次还须要考虑到Type,那么你就会获得一个when嵌套者when的代码块url
fun showByFormatAndType(res: ResBean) {
when (res.format) {
ResBean.RES_FORMAT_IMAGE ->
when (res.type) {
ResBean.RES_TYPE_RED -> showRedImage()
ResBean.RES_TYPE_BURNING -> showBurningImage()
ResBean.RES_TYPE_RED_BURNING -> showRedBurningImage()
ResBean.RES_TYPE_NORMAL -> showNormalImage()
}
ResBean.RES_FORMAT_VIDEO ->
when (res.type) {
ResBean.RES_TYPE_RED -> showRedVideo()
ResBean.RES_TYPE_BURNING -> showBurningVideo()
ResBean.RES_TYPE_RED_BURNING -> showRedBurningVideo()
ResBean.RES_TYPE_NORMAL -> showNormalVideo()
}
else -> showUnKown()
}
}
复制代码
这样的代码带来的困扰其实主要时易读性后后期维护上困难,若是你前期没有作很好的提出封装,那么就更痛苦了。试想一下若是须要添加一个新的format,或者一个type都不太舒服。并且你还得考虑不少得else状况spa
在层级嵌套上,能够考虑将fromat和type作一个积类型,也就合二为一来减小多层嵌套,代码以下:code
fun byFormatAndTypeTodo(res: ResBean) {
with(res) {
when {
format == ResBean.RES_FORMAT_IMAGE && type == ResBean.RES_TYPE_NORMAL -> showNormalImage()
format == ResBean.RES_FORMAT_IMAGE && type == ResBean.RES_TYPE_RED -> showRedImage()
format == ResBean.RES_FORMAT_IMAGE && type == ResBean.RES_TYPE_BURNING -> showBurningImage()
format == ResBean.RES_FORMAT_IMAGE && type == ResBean.RES_TYPE_RED_BURNING -> showRedBurningImage()
format == ResBean.RES_FORMAT_VIDEO && type == ResBean.RES_TYPE_NORMAL -> showNormalVideo()
format == ResBean.RES_FORMAT_VIDEO && type == ResBean.RES_TYPE_RED -> showRedVideo()
format == ResBean.RES_FORMAT_VIDEO && type == ResBean.RES_TYPE_BURNING -> showBurningVideo()
format == ResBean.RES_FORMAT_VIDEO && type == ResBean.RES_TYPE_RED_BURNING -> showRedBurningVideo()
else -> showUnKown()
}
}
}
复制代码
这样一来减小了层级得嵌套,可是牺牲了代码得可读性,最后考虑结合密封来提高可读性。首先定义一个密封类。orm
sealed class ResWithFormatAndType {
data class NormalImageRes(val res: ResBean) : ResWithFormatAndType()
data class RedImageRes(val res: ResBean) : ResWithFormatAndType()
data class BurningImageRes(val res: ResBean) : ResWithFormatAndType()
data class RedAndBurningImageRes(val res: ResBean) : ResWithFormatAndType()
data class NormalVideoRes(val res: ResBean) : ResWithFormatAndType()
data class RedVideoRes(val res: ResBean) : ResWithFormatAndType()
data class BurningVideoRes(val res: ResBean) : ResWithFormatAndType()
data class RedAndBurningVideoRes(val res: ResBean) : ResWithFormatAndType()
object UnkownRes : ResWithFormatAndType()
}
复制代码
以后封装一个方法来获取相应对象
fun getResByFormatWithType(res: ResBean): ResWithFormatAndType = with(res) {
when {
format == ResBean.RES_FORMAT_IMAGE && type == ResBean.RES_TYPE_NORMAL -> NormalImageRes(res)
format == ResBean.RES_FORMAT_IMAGE && type == ResBean.RES_TYPE_RED -> RedImageRes(res)
format == ResBean.RES_FORMAT_IMAGE && type == ResBean.RES_TYPE_BURNING -> BurningImageRes(res)
format == ResBean.RES_FORMAT_IMAGE && type == ResBean.RES_TYPE_RED_BURNING -> RedAndBurningImageRes(res)
format == ResBean.RES_FORMAT_VIDEO && type == ResBean.RES_TYPE_NORMAL -> NormalVideoRes(res)
format == ResBean.RES_FORMAT_VIDEO && type == ResBean.RES_TYPE_RED -> RedVideoRes(res)
format == ResBean.RES_FORMAT_VIDEO && type == ResBean.RES_TYPE_BURNING -> BurningVideoRes(res)
format == ResBean.RES_FORMAT_VIDEO && type == ResBean.RES_TYPE_RED_BURNING -> RedAndBurningVideoRes(res)
else -> ResWithFormatAndType.UnkownRes
}
}
复制代码
最后在使用得地方接口
fun test() {
when (getResWithFormatAndType(resBean) {
is ResWithFormatAndType.NormalImageRes -> showNormalImage()
is ResWithFormatAndType.BurningImageRes -> showBurningImage()
is ResWithFormatAndType.RedImageRes -> showRedImage()
is ResWithFormatAndType.RedAndBurningImageRes -> showRedBurningImage()
is ResWithFormatAndType.BurningVideoRes -> showBurningVideo()
is ResWithFormatAndType.NormalVideoRes -> showNormalVideo()
is ResWithFormatAndType.RedAndBurningVideoRes -> showRedBurningVideo()
is ResWithFormatAndType.RedVideoRes -> showRedVideo()
}
}
复制代码
最终解决后的方案我的以为还不够完善,之前看到过Scala有模式匹配这样的概念,可是在Kotlin中没有找到最终的解决方案,也期许一下Kotlin能早日支持模式匹配这样的概念。资源