Is there any idiomatic way to avoid a huge when? L...
# announcements
p
Is there any idiomatic way to avoid a huge when? Like when(string){ "blabla" -> {generateA} "bleble" -> {generateB} "blibli" -> {generateC} "bloblo" -> {generateE} "blublu" -> {generateD} .... } Is there any pattern that could help me out with this? For instance Command or Factory? This when is going to grow when I add more items, note each item have different behavior The example would be from my ViewModel I send this "type" to my useCase and my useCase decide what to do, because create N UseCase perhaps is a mess...
p
Hmm, the thing is create a map to decide what to do then, right?
n
once you create a map, then you can get it out with the key e.g.
"blabla"
, then call
invoke()
on the returned function
j
Another technique (maybe not applicable to your use-case, but maybe applicable too) is simply to use polymorphism or functions: instead of passing a string identifying what to do, pass what to do, as an instance of an interface or as a function. I.e. instead of
something.execute('blabla')
, use
something.execute(BlablaCommand())
or
something.execute { generateA() }
p
@jbnizet yes that's something I saw, well I put String on this case, but can be whatever, I mean I can create an Enum/Interface and then use polymorphism for this. For example if I select youtube I want to do youtube://mydata/you.be if I want to do Twitter do twitter://tw.er/mydata something like this you know? Each type has a different behaviour but I can use whatever instead of sting so if you want to propose an example with your approach feel free.
r
Copy code
enum class Scheme {
  youtube { override fun uriFor(data: String) = "youtube://$data/you.be" },
  twitter { override fun uriFor(data: String) = "<twitter://tw.er/$data>" };

  abstract fun uriFor(data: String): String
}

fun main(vararg args: String) {
  val schemeName = args[0]
  val data = args[1]
  Scheme.valueOf(schemeName).uriFor(data)
}
Or perhaps more flexible:
Copy code
interface RemoteSystem {
  fun uriFor(data: String): String
}

class YouTube : RemoteSystem {
  override fun uriFor(data: String) = "youtube://$data/you.be"
}

class Twitter : RemoteSystem {
  override fun uriFor(data: String) = "<twitter://tw.er/$data>"
}

enum class Scheme {
  youtube { override val system = YouTube() },
  twitter { override val system = Twitter() };

  abstract val system: RemoteSystem
}

fun main(vararg args: String) {
  val schemeName = args[0]
  val data = args[1]
  Scheme.valueOf(schemeName).system.uriFor(data)
}
Except of course you’d use a proper way of constructing a URI…
Copy code
import java.net.URI

enum class Scheme {
  youtube { override fun uriFor(data: String): URI = URI.create("youtube://$data/").resolve("<http://you.be|you.be>") },
  twitter { override fun uriFor(data: String): URI = URI.create("<twitter://tw.er/>").resolve(data) };

  abstract fun uriFor(data: String): URI
}

fun main(vararg args: String) {
  val schemeName = args[0]
  val data = args[1]
  Scheme.valueOf(schemeName).uriFor(data)
}
Though the more I think about it the more I like the map lookup Nicolas Fränkel suggested, because it makes it explicit that you’re doing a mapping from a string input to a domain object, and forces you to consider the possibility that there is no matching mapping:
Copy code
interface RemoteSystem {
  fun uriFor(data: String): URI
}

class YouTube : RemoteSystem {
  override fun uriFor(data: String): URI = URI.create("youtube://$data/").resolve("<http://you.be|you.be>")
}

class Twitter : RemoteSystem {
  override fun uriFor(data: String): URI = URI.create("<twitter://tw.er/>").resolve(data)
}

val schemes = mapOf(
  "youtube" to YouTube(),
  "twitter" to Twitter(),
)

fun main(vararg args: String) {
  val schemeName = args[0]
  val data = args[1]
  val system = schemes[schemeName] ?: TODO("handle unknown scheme")
  system.uriFor(data)
}
Sorry, thinking about it I don’t really know why I barged into this 5 day old conversation without really thinking about and reading the preceding questions properly. Feel free to ignore.