Motivation: A request can be handled by one of several objects, and we don’t want to hard-wire which object handles it. The handler should be determined at runtime.

Intent: Pass a request along a chain of potential handlers until one of them handles it.

Each handler decides whether to process the request or pass it to the next handler in the chain.

abstract class Logger(private val next: Logger? = null) {
    fun log(level: Int, message: String) {
        if (canHandle(level)) write(message)
        else next?.log(level, message)
    }
    abstract fun canHandle(level: Int): Boolean
    abstract fun write(message: String)
}
 
class InfoLogger(next: Logger? = null) : Logger(next) {
    override fun canHandle(level: Int) = level == INFO
    override fun write(message: String) { println("INFO: $message") }
}
 
class ErrorLogger(next: Logger? = null) : Logger(next) {
    override fun canHandle(level: Int) = level == ERROR
    override fun write(message: String) { println("ERROR: $message") }
}