Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
271 views
in Technique[技术] by (71.8m points)

refactor 'When' logic in kotlin using maps

I am currently refactoring some Kotlin code - I have a nice solution to a simple refactor but unsure of how to do this within the Koltin syntax using maps. Any help would be great!

Current code

here are my data classes:

public sealed class DocumentBody {

    public data class Information(
        val Id: String,
        val name: String,
        val sort: Int = 2
    ) : DocumentBody ()

    public data class Location(
        val name: String,
        val address: String? = null,
        val sort: Int = 3
    ) : DocumentBody()

    public data class Rating(
        val name: String,
        val rating: Int,
        val sort: Int = 3
    ) : DocumentBody()
}

Currently within my code base there is a extension function where it gets some extended info based upon type of context this is:

private fun DocumentBody.getExtendedInfo(
   settings: Settings = Settings()
): String? {
    return if (settings.versions != null) {
        when (this) {
            is DocumentBody.Information ->
                getExtentedInfo(ContentType.Information, settings.versions)
            is DocumentBody.Location ->
                getExtentedInfo(ContentType.Location, settings.versions)
            is DocumentBody.Rating ->
                getExtentedInfo(ContentType.Rating, settings.versions)
        }
    } else {
        when (this) {
            is DocumentBody.Information ->
                 ExtentedInfo[ContentType.Information]
            is DocumentBody.Location ->
                ExtentedInfo[ContentType.Location]
            is DocumentBody.Rating ->
                ExtentedInfo[ContentType.Rating]
        }
    }

Refactoring code

when looking into a nicer way to do this I have created a map for the DocumentBody type to ContextType like so (cannot set a type within the map for this - this may be the issue but unsure):

public val getContentTypeFromDocumentBody: Map<Any, ContentType> = mapOf(
    DocumentBody.Information to ContentType.Information,
    DocumentBody.Location to ContentType.Location,
    DocumentBody.Rating to ContentType.Rating
    )

here then I want to be able to call this and get the ContentType from the key:

getContentTypeFromDocumentBody[docBodyType]

this is currently passing through the data but I want the type. I have explored how to do this with the idea of something like this:

    private fun DocumentBody.getExtendedInfo(settings: Settings = Settings()): String {
     getContentTypeFromDocumentBody.keys.map { docBodyType ->
                when (this) {
                    is docBodyType -> getContentTypeFromDocumentBody[docBodyType]
                    else -> error("invalid document type")
                }
            }
     }

but this doesn't work and creat has red lines under docBodyType on the 4th line.

Basically I want to pass in the type of DocumentBody into this new map to get a Content Type, hope this idea of what I am trying to do makes sense. Any help would be great!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Before I answer your actual question, I have to say it would be more straight-forward to simply make the ContentType a property of DocumentBody like this:

public sealed class DocumentBody(val contentType: ContentType) {

    public data class Information(
        val Id: String,
        val name: String,
        val sort: Int = 2
    ) : DocumentBody(ContentType.Information)

    public data class Location(
        val name: String,
        val address: String? = null,
        val sort: Int = 3
    ) : DocumentBody(ContentType.Location)

    public data class Rating(
        val name: String,
        val rating: Int,
        val sort: Int = 3
    ) : DocumentBody(ContentType.Rating)
}

I recommend doing the above, but to answer your question, you can't simply list class names as if they are instances of something. You need to use ::class to get an actual object to pass around:

public val getContentTypeFromDocumentBody: Map<KClass<out DocumentBody>, ContentType> = mapOf(
    DocumentBody.Information::class to ContentType.Information,
    DocumentBody.Location::class to ContentType.Location,
    DocumentBody.Rating::class to ContentType.Rating
)

and then check it using the ::class of the object you're comparing it to:

private fun DocumentBody.getExtendedInfo(settings: Settings = Settings()): String {
    val contentType = getContentTypeFromDocumentBody[this::class]
        ?: error("invalid document type")
    //...
}

I would also suggest giving your map a descriptive name instead of making it sound like a getter function. Something like contentTypeByDocumentBodyClass.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...