在Android中通过字符串名称获取类,以避免重复我自己

问题描述 投票:0回答:1

所以在我的代码中,我得到了一个字符串列表,这些字符串与枚举中的电影流派相对应。然后,我得到一个元数据文件,并逐一检查每个流派,查看服务器更新该流派的日期是否比我检索这些电影并将其存储在数据库中的日期新。长话短说,元数据文件具有每种流派的类,而我正在重复自己一遍,仅仅是因为我无法考虑如何以编程方式让我的应用知道这一点,例如您正在评估类型ACTION时,应查看成员变量metadata.action。这是我的代码,我已将其截断,但有几十种类型。

TwMetadata

data class TwMetadata (

        @SerializedName("action") var action : Action,
        @SerializedName("adventure") var adventure : Adventure,
        @SerializedName("animation") var animation : Animation,
        @SerializedName("comedy") var comedy : Comedy,

)

在下面的代码中,我已经从服务器中提取了字符串列表,将其转换为体裁枚举,并检查了sharedpreferences元数据文件(spObj)中的上次更新日期,以及上次更新的日期在新提取的元数据文件(metadata.value)中。如果有新数据,我将更改sharedpreferences元数据文件中的日期,该日期将在此完成项的后面提交。然后,我将其发送到一个函数,该函数可以从数据库或Web提取数据,具体取决于我发送的布尔值。理想情况下,我可以摆脱整个“ when”块,而只对每种类型运行一个函数,但是要使其正常工作,他们需要知道它们在元数据文件中对应的类。

  private fun checkGenreDate(genreList: MutableList<GENRE>) : Completable {
    return Completable.create { emitter ->

      var getNew = json.isNullOrEmpty()

      genreList.forEach {
        when (it) {
          GENRE.NULL -> {
          }
          GENRE.ACTION -> {
            if (spObj.action.updated < metadata.value!!.action.updated) {
              getNew = true
              spObj.action = metadata.value!!.action
            }
            loadFromTwApi(it, getNew)
          }
          GENRE.ADVENTURE -> {
            if (spObj.adventure.updated < metadata.value!!.adventure.updated) {
              getNew = true
              spObj.adventure = metadata.value!!.adventure
            }
            loadFromTwApi(it, getNew)
          }
          GENRE.ANIMATION -> {
            if (spObj.animation.updated < metadata.value!!.animation.updated) {
              getNew = true
              spObj.animation = metadata.value!!.animation

            }
            loadFromTwApi(it, getNew)
          }
          GENRE.COMEDY -> {
            if (spObj.comedy.updated < metadata.value!!.comedy.updated) {
              getNew = true
              spObj.comedy = metadata.value!!.comedy
            }
            loadFromTwApi(it, getNew)
          }
          GENRE.RANDOM -> {
          }
          GENRE.THEATER -> {
            loadTheaterData()
          }
        }
      }
      emitter.onComplete()
    }
  }

我的枚举类

enum class GENRE {
  NULL,
  ACTION,
  ADVENTURE,
  ANIMATION,
  COMEDY,
  RANDOM,
  THEATER;

  companion object {
    fun getGenreByName(name: String) = try {
      (name.toUpperCase(Locale.getDefault()))
    } catch (e: IllegalArgumentException) {
      null
    }
  }
android kotlin dry data-class
1个回答
0
投票

[我建议使用通用的sealed class,它具有抽象的元数据get和set方法,并且在密封的类中包含静态查找方法。 Kotlin几乎可以将枚举转换为类层次结构,因此您可以在其中共享和实施功能。

因此仅是动作和冒险,这是一个函数updateAllGenres,它将更新所有元数据。

fun updateAllGenres( spObj: TwMetadata, metadata: MetadataFile ) {
    Genre.forEach {
        it.maybeUpdateSharedMetadata( spObj, metadata )
    }
}

sealed class Genre < T : GenreMetadata > {
    companion object {
        fun forEach( callback: ( Genre < * > ) -> Unit ) {
            Genre::class.sealedSubclasses.forEach {
                callback( it.objectInstance as Genre < * > )
            }
        }
    }

    fun maybeUpdateSharedMetadata( spObj: TwMetadata, metadata: MetadataFile ): Boolean {
        val genreMetadataInFile = getGenreMetadata( metadata.value!! )
        return getGenreMetadata( spObj ).updated < genreMetadataInFile.updated
            .also { setGenreMetadataInDictionary( spObj, genreMetadataInFile )
        }
    }

    protected abstract fun getGenreMetadata( metadata: TwMetadata ): T
    protected abstract fun setGenreMetadataInDictionary( metadata: TwMetadata, genreMetadata: T )
}

object ActionGenre : Genre < Action >() {
    override fun getGenreMetadata( metadata: TwMetadata ): Action {
        return metadata.action
    }

    override fun setGenreMetadataInDictionary( metadata: TwMetadata, genreMetadata: Action ) {
        metadata.action = genreMetadata
    }
}

object AdventureGenre : Genre < Adventure >() {
    override fun getGenreMetadata( metadata: TwMetadata ): Adventure {
        return metadata.adventure
    }

    override fun setGenreMetadataInDictionary( metadata: TwMetadata, genreMetadata: Adventure ) {
        metadata.adventure = genreMetadata
    }
}

还需要进行一些调整才能准确地实现您的功能,但是我敢肯定,您会明白的。另外,您可能想做得更多,并结合使用密封的子类和保存元数据的类ActionAdventure等,但这需要更多工作。

上面的接口供参考:

interface Action : GenreMetadata {}
interface Adventure : GenreMetadata {}

interface GenreMetadata {
    val updated: Long
}

interface TwMetadata {
    var action: Action
    var adventure: Adventure
}

interface MetadataFile {
    val value: TwMetadata?
}
© www.soinside.com 2019 - 2024. All rights reserved.