Chain of Responsibility – Patrones de Diseño
Antonio Leiva

El patrón de diseño Chain of Responsibility es un patrón de diseño de software que permite a varios objetos intentar resolver una solicitud.

En lugar de enviar una solicitud directamente a un objeto específico, se envía a una cadena de objetos que pueden resolverla.

Cada objeto en la cadena tiene la oportunidad de manejar la solicitud. Si un objeto no puede manejarla, se la pasa al siguiente objeto en la cadena hasta que se encuentra uno que pueda manejarla.

Este patrón es útil cuando hay varias posibles manejadores para una solicitud y no se sabe de antemano cuál es el adecuado.

También puede ser útil para evitar que una solicitud se envíe a un objeto que no puede manejarla, lo que puede mejorar el rendimiento y evitar errores.

Un ejemplo típico de la cadena de responsabilidad es un sistema de procesamiento de pagos.

Puede haber varios tipos de pagos, como pagos con tarjeta de crédito, pagos con PayPal y pagos en efectivo. Cada uno de estos tipos de pago puede ser manejado por un objeto diferente.

En lugar de tener que comprobar cada tipo de pago y enviar la solicitud al objeto adecuado, se puede crear una cadena de objetos que manejan cada tipo de pago y enviar la solicitud a la cadena. La cadena se encargará de enviar la solicitud al objeto adecuado.

En Kotlin, la cadena de responsabilidad se puede implementar de la siguiente manera.

Primero, nos creamos la interfaz que tiene que implementar un procesador de pago:

interface PaymentHandler {
    fun setNext(handler: PaymentHandler): PaymentHandler
    fun handle(request: PaymentRequest): PaymentResponse
}

Necesitamos varias clases que representen la petición de pago, la respuesta y los tipos de pago:

data class PaymentRequest(val paymentMethod: PaymentMethod)

data class PaymentResponse(val success: Boolean, val message: String)

enum class PaymentMethod {
    CREDIT_CARD,
    PAYPAL,
    CASH
}

Aquí tienes tres posibles implementaciones: mediante tarjeta de crédito, PayPal, o efectivo:

class CreditCardHandler : PaymentHandler {
    private var next: PaymentHandler? = null

    override fun setNext(handler: PaymentHandler): PaymentHandler {
        next = handler
        return handler
    }

    override fun handle(request: PaymentRequest): PaymentResponse {
        if (request.paymentMethod == PaymentMethod.CREDIT_CARD) {
            // Procesar pago con tarjeta de crédito
            return PaymentResponse(true, "Pago procesado con éxito")
        } else {
            if (next == null) {
                throw IllegalStateException("No se encontró un manejador adecuado para el pago")
            }
            return next!!.handle(request)
        }
    }
}

class PaypalHandler : PaymentHandler {
    private var next: PaymentHandler? = null

    override fun setNext(handler: PaymentHandler): PaymentHandler {
        next = handler
        return handler
    }

    override fun handle(request: PaymentRequest): PaymentResponse {
        if (request.paymentMethod == PaymentMethod.PAYPAL) {
            // Procesar pago con PayPal
            return PaymentResponse(true, "Pago procesado con éxito")
        } else {
            if (next == null) {
                throw IllegalStateException("No se encontró un manejador adecuado para el pago")
            }
            return next!!.handle(request)
        }
    }
}

class CashHandler : PaymentHandler {
    private var next: PaymentHandler? = null

    override fun setNext(handler: PaymentHandler): PaymentHandler {
        next = handler
        return handler
    }

    override fun handle(request: PaymentRequest): PaymentResponse {
        if (request.paymentMethod == PaymentMethod.CASH) {
            // Procesar pago en efectivo
            return PaymentResponse(true, "Pago procesado con éxito")
        } else {
            if (next == null) {
                throw IllegalStateException("No se encontró un manejador adecuado para el pago")
            }
            return next!!.handle(request)
        }
    }

}

Y finalmente indicamos la cadena en con el orden en el que se ejecutará cada handler, con el fin de saber si puede o no consumir esa petición:

val chain: PaymentHandler = CreditCardHandler()
    .setNext(PaypalHandler())
    .setNext(CashHandler())

Y se le indica a la cadena que gestione la petición:

val response = chain.handle(PaymentRequest(PaymentMethod.PAYPAL))
println(response.message) // Imprimirá "Pago procesado con éxito"

En este ejemplo, se creó una cadena de manejadores para diferentes métodos de pago. Cuando se envía una solicitud de pago a la cadena, se pasa a cada manejador hasta que se encuentra uno que pueda manejar el tipo de pago especificado en la solicitud.

Esto permite a la aplicación manejar diferentes tipos de pagos de manera flexible y eficiente.

En resumen, el patrón de diseño Chain of Responsibility es un patrón de diseño de software que permite a varios objetos intentar resolver una solicitud.

Esto puede ser útil cuando hay varios posibles manejadores para una solicitud y no se sabe de antemano cuál es el adecuado.

En Kotlin, se puede implementar mediante la creación de una interfaz de manejador de pagos y clases que implementan esta interfaz para manejar diferentes tipos de pagos.

Luego se pueden agregar estos manejadores a una cadena en el orden deseado y enviar solicitudes de pago a la cadena para ser manejadas por el manejador adecuado.

Quizá también te interese…

Las reglas FIRST de los tests

Las reglas FIRST de los tests

Las reglas FIRST son un conjunto de principios que se utilizan para diseñar y escribir tests de software de manera efectiva. Las siglas FIRST significan: F - Fast: Un test debe ser rápido de ejecutar. I - Independent: Un test debe ser independiente de otros tests y...

¿Qué son los dobles de test?

¿Qué son los dobles de test?

Los dobles de prueba (también conocidos como "doubles" o "fakes") son herramientas comunes en la programación y en particular en el testing de software. Se utilizan para simular el comportamiento de una dependencia de una aplicación en un entorno de pruebas, sin tener...

Kata del TicTacToe en Kotlin

Kata del TicTacToe en Kotlin

Escribe el código para representar una entidad que almacene el tablero de juego del 3 en raya, y que además tenga: Un método move() con 2 parámetros, fila y columna, que permita añadir un movimiento al tablero Un método findWinner(), que devuelva el ganador (X, Y o...

0 comentarios

Enviar un comentario

Los datos personales que proporciones a través de este formulario quedarán registrados en un fichero de DevExpert, S.L.U., con el fin de gestionar los comentarios que realizas en este blog. La legitimación se realiza a través del consentimiento de la parte interesada. Si no se acepta, no podrás comentar en este blog. Los datos que proporciona solo se utilizan para evitar el correo no deseado y no se usarán para nada más. Puede ejercer los derechos de acceso, rectificación, cancelación y oposición en contacto@devexperto.com.

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acepto la política de privacidad *