Command – Patrones de Diseño

Avatar
4 min lectura

El patrón de diseño Command es un patrón de diseño de software que se utiliza para encapsular una solicitud como un objeto, de modo que se pueda parametrizar con diferentes solicitudes, enviar solicitudes por separado a colas o registrar y reproducir operaciones.

Este patrón se basa en la idea de tratar las operaciones de la misma manera que los datos, lo que permite tratar a las operaciones de forma genérica y separar la ejecución de una operación de su implementación.

Ejemplo 1: Sistema de luces inteligentes

Un ejemplo común de la utilización del patrón Command es en la implementación de un sistema de control de luces en una casa inteligente.

En este caso, cada luz podría ser representada por un objeto que puede ejecutar objetos de tipo Command, y cada acción que se pueda realizar sobre una luz (encender, apagar, cambiar de color, etc.) se implementaría como una clase concreta que implemente la interfaz Command.

De esta forma, se pueden crear diferentes objetos Command que representen diferentes acciones sobre una luz, y enviarlos al objeto Luz para que se ejecuten.

En Kotlin, podemos implementar el patrón Command de la siguiente manera:

interface Command {
  fun execute()
}

class TurnOnLight: Command {
  override fun execute() {
    // Code to turn on a light
  }
}

class TurnOffLight: Command {
  override fun execute() {
    // Code to turn off a light
  }
}

class Light {
  private val commands = mutableListOf<Command>()

  fun addCommand(command: Command) {
    commands.add(command)
  }

  fun executeCommands() {
    commands.forEach { it.execute() }
  }
}

fun main() {
  val light = Light()
  light.addCommand(TurnOnLight())
  light.addCommand(TurnOffLight())
  light.executeCommands()
}

En este ejemplo, hemos creado una interfaz Command que define el método execute(), que será implementado por las clases concretas que representen diferentes acciones sobre una luz. Luego, hemos creado dos clases concretas que implementan la interfaz Command: TurnOnLight y TurnOffLight. Estas clases contienen la lógica para encender y apagar una luz, respectivamente.

Finalmente, hemos creado una clase Light que tiene una lista de objetos Command y un método que permite añadir nuevos objetos Command a esta lista.

La clase Light también tiene un método executeCommands() que itera sobre la lista de objetos Command y ejecuta el método execute() de cada uno de ellos. De esta forma, se pueden enviar diferentes acciones a una luz y ejecutarlas en el orden en que se han agregado a la lista de commands.

Por ejemplo, en el código anterior podríamos crear una clase ChangeLightColor que implemente la interfaz Command y agregarla a la lista de commands en la luz. Cuando se llame al método executeCommands(), se ejecutarán en orden las acciones de encender la luz, cambiarle el color y apagarla.

De esta forma, el patrón Command nos permite tratar a las operaciones de un sistema de forma genérica y separar su ejecución de su implementación, lo que nos permite crear sistemas flexibles y modulares.

Ejemplo 2: Sistema de ventanas de escritorio

En este ejemplo, hemos creado una interfaz Command que define el método execute(), que será implementado por las clases concretas que representen diferentes acciones sobre una ventana emergente.

Luego, hemos creado tres clases concretas que implementan la interfaz Command: OpenWindow, CloseWindow y ResizeWindow.

Estas clases contienen la lógica para abrir, cerrar y cambiar el tamaño de una ventana emergente, respectivamente.

Finalmente, hemos creado una clase PopUpWindow que tiene una lista de objetos Command y un método que permite añadir nuevos objetos Command a esta lista. La clase PopUpWindow también tiene un método executeCommands() que itera sobre la lista de objetos Command y ejecuta el método execute() de cada uno de ellos. De esta forma, se pueden enviar diferentes acciones a una ventana emergente y ejecutarlas en el orden en que se han agregado a la lista de commands.

Aquí puedes ver un ejemplo en Kotlin de cómo se podría implementar el patrón Command en este caso:

interface Command {
  fun execute()
}

class OpenWindow: Command {
  override fun execute() {
    // Código para abrir una ventana emergente
  }
}

class CloseWindow: Command {
  override fun execute() {
    // Código para cerrar una ventana emergente
  }
}

class ResizeWindow: Command {
  override fun execute() {
    // Código para cambiar de tamaño una ventana emergente
  }
}

class PopUpWindow {
  private val commands = mutableListOf<Command>()

  fun addCommand(command: Command) {
    commands.add(command)
  }

  fun executeCommands() {
    commands.forEach { it.execute() }
  }
}

fun main() {
  val window = PopUpWindow()
  window.addCommand(OpenWindow())
  window.addCommand(ResizeWindow())
  window.addCommand(CloseWindow())
  window.executeCommands()
}

Conclusión

En conclusión, el patrón de diseño Command es un patrón de diseño de software que nos permite encapsular una solicitud como un objeto y tratar a las operaciones de forma genérica y separada de su implementación.

Esto nos permite crear sistemas flexibles y modulares que permiten parametrizar diferentes solicitudes, enviar solicitudes por separado a colas o registrar y reproducir operaciones.

El patrón Command es ampliamente utilizado en diferentes contextos y puede ser implementado en cualquier lenguaje de programación, como lo hemos visto en nuestro ejemplo en Kotlin.