1. Factory Method

[THEORY]

[PREDICT]

Read the code carefully before you run it.

prediction.kt
interface Notifier { fun notify(user: String, message: String) }

class EmailNotifier : Notifier {
    override fun notify(user: String, message: String) = println("Email to " + user + ": " + message)
}

fun notifierFor(channel: String): Notifier = when (channel) {
    "email" -> EmailNotifier()
    else -> throw IllegalArgumentException("Unknown channel: " + channel)
}

fun main() {
    notifierFor("email").notify("lena", "Welcome")
    notifierFor("sms").notify("omar", "Ping")
}

What does this program print? And where would you make the change to support the sms channel, so that main stays exactly as it is?

[TASK]

Finish the factory. notifierFor must return an EmailNotifier for the channel email and an SmsNotifier for sms, and throw IllegalArgumentException for any other channel. Each notifier's format(user, message) returns channel|user|message, for example email|lena|Welcome. The caller must never name a concrete class itself. Then use notifierFor("email") and print the formatted message in main.

task.kt
// TODO: finish the factory. `notifierFor` must return an `EmailNotifier` for // "email" and an `SmsNotifier` for "sms", and throw IllegalArgumentException // for any other channel. The caller must never name a concrete class itself. interface Notifier { fun format(user: String, message: String): String } class EmailNotifier : Notifier { override fun format(user: String, message: String): String { // TODO: return "email|" + user + "|" + message TODO() } } class SmsNotifier : Notifier { override fun format(user: String, message: String): String { // TODO: return "sms|" + user + "|" + message TODO() } } fun notifierFor(channel: String): Notifier { // TODO: return the matching Notifier, or throw for an unknown channel. TODO() } fun main() { // TODO: use notifierFor("email") and print the formatted message. }

Before you get a hint: what have you tried, and where exactly are you stuck?

[COMPREHENSION CHECK]

1. What is the main benefit of a factory method?

2. When is a factory method likely over-engineering?

3. What does the calling code depend on when it uses a factory?