lundi 3 mai 2021

Converting Kotlin functional programming code to object oriented classes

I have the code for the design pattern Chain Of Resposibility in functional programming. I'm trying to convert it to regular OOP classes. Following is the working code for the design pattern:

Functional Programming Code

enum class LogLevel {
    INFO, DEBUG, WARNING, ERROR, FUNCTIONAL_MESSAGE, FUNCTIONAL_ERROR;

    companion object {
        public fun all(): Array<LogLevel> {
            return values()
        }
    }
}

/**
 * Handler: Contains a method for building a chain of handlers. 
 * It also declares a method for executing a request.
 */
fun interface Logger {
    fun message(message: String, severity: LogLevel)

    fun appendNext(nextLogger: Logger): Logger {
        return Logger { message, severity ->
            message(message, severity)
            nextLogger.message(message, severity)
        }
    }
}

/**
 * Base Handler: Base handler is an optional class where you can put the boilerplate
 * code that’s common to all handler classes.
 *
 * @param writeMessage is the container that acts as the next link in the chain of handlers.
 */
fun writeLogger(vararg levels: LogLevel,
    writeMessage: (String) -> Unit
): Logger {
    val specifiedLevelsSet = EnumSet.copyOf(listOf(*levels))
    return Logger { message, requestedLogLevel ->
        if (specifiedLevelsSet.contains(requestedLogLevel)) {
            writeMessage(message)
        }
    }
}

/**
 * Concrete Handlers: Concrete handlers contain the actual code for processing requests.
 */
fun consoleLogger(vararg levels: LogLevel) =
    writeLogger(*levels) { message -> System.err.println("Writing to console: $message") }

fun emailLogger(vararg levels: LogLevel) =
    writeLogger(*levels) { message -> System.err.println("Sending via email: $message") }

fun fileLogger(vararg levels: LogLevel) =
    writeLogger(*levels) { message -> System.err.println("Writing to Log File: $message") }

/**
 * Client:
 */
fun main() {

    // Build an immutable chain of responsibility
    val logger = consoleLogger(*LogLevel.all())
        .appendNext(emailLogger(LogLevel.FUNCTIONAL_MESSAGE, LogLevel.FUNCTIONAL_ERROR))
        .appendNext(fileLogger(LogLevel.WARNING, LogLevel.ERROR))

    // Handled by consoleLogger since it has been set to log all levels
    logger.message("Entering function ProcessOrder().", LogLevel.DEBUG)
    logger.message("Order record retrieved.", LogLevel.INFO)

    // Handled by consoleLogger and emailLogger since the emailLogger
    // implements FUNCTIONAL_ERROR & FUNCTIONAL_MESSAGE
    logger.message(
        "Unable to Process Order ORD1 Dated D1 For Customer C1.",
        LogLevel.FUNCTIONAL_ERROR
    )
    logger.message("Order Dispatched.", LogLevel.FUNCTIONAL_MESSAGE)

    // Handled by consoleLogger and fileLogger since fileLogger implements WARNING & ERROR
    logger.message("Customer Address details missing in Branch DataBase.", LogLevel.WARNING)
    logger.message("Customer Address details missing in Organization DataBase.", LogLevel.ERROR)
}

My Question

I want to convert the functional programming code to the regular classes for studying purposes. I want to convert fun interface to regular interface and convert the function writeLogger() to abstract class/regular class BaseLogger, consoleLogger() to the class ConsoleLogger, emailLogger() to EmailLogger and so on.


My attempt to convert to OOP classes

I'm having a hard time distributing the functional code above in the various classes below:

interface Logger {
    fun appendNext(nextLogger: Logger)
    fun message(message: String, severity: LogLevel)
}

abstract class BaseLogger(vararg levels: LogLevel) : Logger {
    private var severity: LogLevel? = null
    private var nextLogger: Logger? = null
    private val specifiedLevelsSet = EnumSet.copyOf(listOf(*levels))

    override fun appendNext(nextLogger: Logger) {
        message(message, severity)
        this.nextLogger = nextLogger    // This may be incorrect
    }

    override fun message(message: String, severity: LogLevel) {
        // what to write here?
    }
}

class ConsoleLogger(vararg level: LogLevel) : BaseLogger(*level) {
    private val message: String? = null

    override fun appendNext(nextLogger: Logger) {
        super.appendNext(nextLogger)
        System.err.println("Writing to console: $message")   // Maybe confused here.
    }

    override fun message(message: String, severity: LogLevel) {
        // what to write here?
    }
}

Any input would be much appreciated.

Aucun commentaire:

Enregistrer un commentaire