Let's say I have two objects in Kotlin:
// IOSIdentifiers.kt
object IOSIdentifiers {
const val STRING_1 = "some_ios_specific_identifier_string1"
const val STRING_2 = "some_ios_specific_identifier_string2"
}
// IOSIdentifiers.kt
object AndroidIdentifiers {
const val STRING_1 = "some_android_specific_identifier_string1"
const val STRING_2 = "some_android_specific_identifier_string2"
}
// Identifiers.kt
object Identifiers {
// Pseudo code:
if(platform == "iOS") IOSIdentifiers else AndroidIdentifiers
}
and I want to use them like so: someFunction(Identifiers.STRING_1)
, how I can do it?
I tried this:
// Identifiers.kt
object Identifiers {
val IDENTIFIERS
get() = if (platform == "iOS") IOSIdentifiers else AndroidIdentifiers
}
but then I need to do someFunction(Identifiers.IDENTIFIERS.STRING_1)
which is not what I want.
I also tried this:
// Identifiers.kt
val Identifiers
get() = if (Configuration.isIOS) IOSIdentifiers else AndroidIdentifiers
but then I lost typings, because val Identifiers
is Any
type.
CodePudding user response:
If you are not allowed to modify the declaration of the 2 identifier objects, it will be more verbose because Kotlin's type system is nominal (and you can't retroactively implement an interface after declaring a class). But you can use delegation like this:
val platform="iOS"
// IOSIdentifiers.kt
object IOSIdentifiers {
const val STRING_1 = "some_ios_specific_identifier_string1"
const val STRING_2 = "some_ios_specific_identifier_string2"
}
// IOSIdentifiers.kt
object AndroidIdentifiers {
const val STRING_1 = "some_android_specific_identifier_string1"
const val STRING_2 = "some_android_specific_identifier_string2"
}
object Identifier{
val STRING_1: String
get() = if (platform== "iOS") IOSIdentifiers.STRING_1 else AndroidIdentifiers.STRING_1
val STRING_2: String
get() = if (platform== "iOS") IOSIdentifiers.STRING_2 else AndroidIdentifiers.STRING_2
}
fun main() {
print(Identifier.STRING_1)
print(Identifier.STRING_2)
}
On the other hand if you can modify the declaration, then you can declare an abstract class that declares both String fields and make the objects extend them, like this:
object AndroidIdentifiers : IIdentifiers() {
override val STRING_1 = "some_android_specific_identifier_string1"
override val STRING_2 = "some_android_specific_identifier_string2"
}
object IOSIdentifiers : IIdentifiers(){
override val STRING_1 = "some_ios_specific_identifier_string1"
override val STRING_2 = "some_ios_specific_identifier_string2"
}
abstract class IIdentifiers {
abstract val STRING_1 : String
abstract val STRING_2 : String
}
val Identifiers = if (platform== "iOS") IOSIdentifiers else AndroidIdentifiers
}
Another way is to use interface delegation (almost the same idea but use interface instead): https://kotlinlang.org/docs/delegation.html
val platform= "iOS"
val delegate= if (platform== "iOS") IOSIdentifiers else AndroidIdentifiers
// IOSIdentifiers.kt
object AndroidIdentifiers : IIdentifiers {
override val STRING_1 = "some_android_specific_identifier_string1"
override val STRING_2 = "some_android_specific_identifier_string2"
}
object IOSIdentifiers : IIdentifiers{
override val STRING_1 = "some_ios_specific_identifier_string1"
override val STRING_2 = "some_ios_specific_identifier_string2"
}
interface IIdentifiers {
val STRING_1 : String
val STRING_2 : String
}
object Identifier : IIdentifiers by delegate
CodePudding user response:
You can make a common interface. For succinctness, you can give that interface a companion object that implements the self-same interface and use delegation to pick the right one. This requires that the platform
is set on Configuration
before this companion object is ever referenced.
object IOSIdentifiers: Identifiers {
override val string1 = "some_ios_specific_identifier_string1"
override val string2 = "some_ios_specific_identifier_string2"
}
object AndroidIdentifiers: Identifiers {
override val string1 = "some_android_specific_identifier_string1"
override val string2 = "some_android_specific_identifier_string2"
}
interface Identifiers {
val string1: String
val string2: String
companion object: Identifiers by when (Configuration.platform) {
"IOS" -> IOSIdentifiers
"Android" -> AndroidIdentifiers
else -> error("Unknown platform ${Configuration.platform}")
}
}
But if this is a multi-platform project, you can use expect/actual to do this is a more sensible way.
expect class Identifiers {
val string1: String
val string2: String
}
// In iOS module:
actual class Identifiers {
actual val string1 = "some_ios_specific_identifier_string1"
actual val string2 = "some_ios_specific_identifier_string2"
}
// In Android module:
actual class Identifiers {
actual val string1 = "some_android_specific_identifier_string1"
actual val string2 = "some_android_specific_identifier_string2"
}