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:
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)
}
I converted the functional programming code to the regular classes for learning purposes. I converted fun interface
to regular interface
and function writeLogger()
to abstract class/regular class BaseLogger
, consoleLogger()
to the class ConsoleLogger
, emailLogger()
to EmailLogger
and so on.
Following is the OOP code I managed so far but EmailLogger
is not getting called for the same main() function written above:
abstract class Logger(vararg levels: LogLevel) {
private var nextLogger: Logger? = null
private val specifiedLevelsSet = EnumSet.copyOf(listOf(*levels))
fun appendNext(nextLogger: Logger): Logger {
this.nextLogger = nextLogger
return this
}
fun message(message: String, severity: LogLevel) {
if (specifiedLevelsSet.contains(severity)) {
log(message)
}
nextLogger?.message(message, severity)
}
abstract fun log(message: String)
}
class ConsoleLogger(vararg level: LogLevel) : Logger(*level) {
override fun log(message: String) {
System.err.println("Writing to console: $message")
}
}
class EmailLogger(vararg level: LogLevel) : Logger(*level) {
override fun log(message: String) {
System.err.println("Sending via email: $message")
}
}
class FileLogger(vararg level: LogLevel) : Logger(*level) {
override fun log(message: String) {
System.err.println("Writing to Log File: $message")
}
}
Any input would be much appreciated.
I replaced the fun interface
with an abstract class
with the chain making capability:
abstract class Logger(vararg levels: LogLevel) {
private var nextLogger: Logger? = null
private val specifiedLevelsSet = EnumSet.copyOf(listOf(*levels))
fun appendNext(nextLogger: Logger) {
this.nextLogger = nextLogger
}
fun message(message: String, severity: LogLevel) {
if (specifiedLevelsSet.contains(severity)) {
log(message)
}
nextLogger?.message(message, severity)
}
abstract fun log(message: String)
}
Converted the functions of implementation to various classes:
class ConsoleLogger(vararg level: LogLevel) : Logger(*level) {
override fun log(message: String) {
System.err.println("Writing to console: $message")
}
}
class EmailLogger(vararg level: LogLevel) : Logger(*level) {
override fun log(message: String) {
System.err.println("Sending via email: $message")
}
}
class FileLogger(vararg level: LogLevel) : Logger(*level) {
override fun log(message: String) {
System.err.println("Writing to Log File: $message")
}
}
fun main() {
// Build an immutable chain of responsibility
val logger = ConsoleLogger(*LogLevel.all())
val emailLogger = EmailLogger(LogLevel.FUNCTIONAL_MESSAGE, LogLevel.FUNCTIONAL_ERROR)
val fileLogger = FileLogger(LogLevel.WARNING, LogLevel.ERROR)
logger.appendNext(emailLogger)
emailLogger.appendNext(fileLogger)
// 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)
}