Kotlin - categorized subenums

118 Views Asked by At

I am trying to implement a Role class/interface/enum that I can use throughout my program. I want the roles to be somewhat categorized - I want some roles to be of type A, some roles to be of type B, and some roles to be part of multiple types. I want to be able to know all the roles from each type - so an enum/sealed class structure is the idea. I tried the following implementation -

sealed interface UserRole {
  val roleName: String
}

enum class RoleA(override val roleName: String): UserRole {
  A(roleName = "A"),
  B(roleName = "B"),
  C(roleName = "C"),
  D(roleName = "D");

  companion object {
    fun fromRoleName(roleName: String): RoleA? =
        values().singleOrNull { it.roleName == roleName }
  }
}

enum class RoleB(override val roleName: String, val secondParam: String): UserRole {
  A(roleName = "A", secondParam = "A"),
  E(roleName = "E", secondParam = "E"),
  F(roleName = "F", secondParam = "F");

  companion object {
    fun fromRoleName(roleName: String): RoleB? =
        values().singleOrNull { it.roleName == roleName }
  }
}

As you can see, A is part of both enums, but I would ideally want them to be the same object. Likewise I want to have the ability to create more of these enums in the future in case I need more types of roles.

Before I tried sealed interfaces, I simply had 1 big enum called UserRole that simply had all the values, and I used another class called RoleType and a simple mapping between the two to get what I wanted, but I don't think it does exactly what I want. Can anyone suggest a better way to categorize enum values?

1

There are 1 best solutions below

2
greyhairredbear On BEST ANSWER

You could reflect your roles in the type system by defining a sealed interface for each role type like this:

sealed interface Type1 {
    val t: Int
    fun test()
}

sealed interface Type2 {
    val s: String
}

Then your Role class could be defined as a sealed class and every class could implement your Role types as fit.

sealed class Role

class A(override val t: Int, override val s: String) : Role(), Type1, Type2 {
    override fun test() {
        print("hello")
    }
}

class B(override val s: String) : Role(), Type2

This does bring some overhead in the amount of code necessary to define each Role, so be aware of this when weighing pros and cons of each variant.