stringtranslate.com

Patrón de comando

En programación orientada a objetos , el patrón de comando es un patrón de diseño de comportamiento en el que se utiliza un objeto para encapsular toda la información necesaria para realizar una acción o desencadenar un evento en un momento posterior. Esta información incluye el nombre del método, el objeto propietario del método y los valores de los parámetros del método.

Cuatro términos siempre asociados con el patrón de comando son comando , receptor , invocador y cliente . Un objeto de comando conoce el receptor e invoca un método del receptor. Los valores de los parámetros del método del receptor se almacenan en el comando. El objeto receptor para ejecutar estos métodos también se almacena en el objeto de comando mediante agregación . Luego, el receptor hace el trabajo cuando se llama al execute()método al mando . Un objeto invocador sabe cómo ejecutar un comando y, opcionalmente, lleva la contabilidad sobre la ejecución del comando. El invocador no sabe nada acerca de un comando concreto, solo conoce la interfaz del comando . Los objetos invocadores, objetos de comando y objetos receptores están en manos de un objeto cliente , el cliente decide qué objetos receptores asigna a los objetos de comando y qué comandos asigna al invocador. El cliente decide qué comandos ejecutar en qué puntos. Para ejecutar un comando, pasa el objeto de comando al objeto invocador.

El uso de objetos de comando facilita la construcción de componentes generales que necesitan delegar, secuenciar o ejecutar llamadas a métodos en el momento que elijan sin la necesidad de conocer la clase del método o los parámetros del método. El uso de un objeto invocador permite realizar cómodamente la contabilidad sobre las ejecuciones de comandos, así como implementar diferentes modos para los comandos, que son administrados por el objeto invocador, sin necesidad de que el cliente esté al tanto de la existencia de contabilidad o modos.

Las ideas centrales de este patrón de diseño reflejan fielmente la semántica de funciones de primera clase y funciones de orden superior en lenguajes de programación funcionales . Específicamente, el objeto invocador es una función de orden superior de la cual el objeto de comando es un argumento de primera clase.

Descripción general

El patrón de diseño comando [1] es uno de los veintitrés patrones de diseño GoF bien conocidos que describen cómo resolver problemas de diseño recurrentes para diseñar software orientado a objetos flexible y reutilizable, es decir, objetos que son más fáciles de implementar, cambiar, probar y reutilizar.

El uso del patrón de diseño de comandos puede resolver estos problemas: [2]

Implementar (cablear) una solicitud directamente en una clase es inflexible porque acopla la clase a una solicitud particular en tiempo de compilación, lo que hace imposible especificar una solicitud en tiempo de ejecución.

El uso del patrón de diseño de comandos describe la siguiente solución:

Esto permite configurar una clase con un objeto de comando que se utiliza para realizar una solicitud. La clase ya no está acoplada a una solicitud particular y no tiene conocimiento (es independiente) de cómo se lleva a cabo la solicitud.

Consulte también el diagrama de secuencia y clase UML a continuación.

Estructura

Diagrama de secuencia y clase UML

Un ejemplo de diagrama de secuencia y clase UML para el patrón de diseño Comando. [3]

En el diagrama de clases UML anterior , la clase no implementa una solicitud directamente. En cambio, se refiere a la interfaz para realizar una solicitud ( ), lo que la hace independiente de cómo se realiza la solicitud. La clase implementa la interfaz realizando una acción en un receptor ( ).InvokerInvokerCommandcommand.execute()InvokerCommand1Commandreceiver1.action1()

El diagrama de secuencia UML muestra las interacciones en tiempo de ejecución: El objeto llama a un objeto. llama a un objeto, que realiza la solicitud.Invokerexecute()Command1Command1action1()Receiver1

diagrama de clases UML

Diagrama UML del patrón de comando.

Usos

Botones GUI y elementos de menú
En la programación Swing y Borland Delphi , an Actiones un objeto de comando. Además de la capacidad de ejecutar el comando deseado, una acción puede tener un icono asociado, un método abreviado de teclado, texto de información sobre herramientas, etc. Un botón de la barra de herramientas o un componente de elemento de menú se puede inicializar completamente usando solo el objeto Acción .
Grabación de macros
Si todas las acciones del usuario están representadas por objetos de comando, un programa puede registrar una secuencia de acciones simplemente manteniendo una lista de los objetos de comando a medida que se ejecutan. Luego puede "reproducir" las mismas acciones ejecutando los mismos objetos de comando nuevamente en secuencia. Si el programa incorpora un motor de secuencias de comandos, cada objeto de comando puede implementar un método toScript() y las acciones del usuario se pueden registrar fácilmente como secuencias de comandos.
codigo movil
Al utilizar lenguajes como Java, donde el código se puede transmitir/sorber de una ubicación a otra a través de URLClassloaders y Codebases, los comandos pueden permitir que se entreguen nuevos comportamientos a ubicaciones remotas (comando EJB, Master Worker).
Deshacer multinivel
Si todas las acciones del usuario en un programa se implementan como objetos de comando, el programa puede mantener una pila de los comandos ejecutados más recientemente. Cuando el usuario quiere deshacer un comando, el programa simplemente muestra el objeto de comando más reciente y ejecuta su método deshacer() .
Redes
Es posible enviar objetos de comando completos a través de la red para que se ejecuten en otras máquinas, por ejemplo, acciones de jugadores en juegos de computadora.
Procesamiento en paralelo
Donde los comandos se escriben como tareas en un recurso compartido y se ejecutan mediante muchos subprocesos en paralelo (posiblemente en máquinas remotas; esta variante a menudo se denomina patrón Maestro/Trabajador)
Barras de progreso
Supongamos que un programa tiene una secuencia de comandos que ejecuta en orden. Si cada objeto de comando tiene un método getEstimatedDuration() , el programa puede estimar fácilmente la duración total. Puede mostrar una barra de progreso que refleja de manera significativa qué tan cerca está el programa de completar todas las tareas.
Grupos de subprocesos
Una clase típica de grupo de subprocesos de propósito general podría tener un método público addTask() que agrega un elemento de trabajo a una cola interna de tareas en espera de ser realizadas. Mantiene un grupo de subprocesos que ejecutan comandos de la cola. Los elementos de la cola son objetos de comando. Normalmente, estos objetos implementan una interfaz común como java.lang.Runnable que permite que el grupo de subprocesos ejecute el comando incluso aunque la clase del grupo de subprocesos se haya escrito sin ningún conocimiento de las tareas específicas para las que se utilizaría.
Comportamiento transaccional
De manera similar a deshacer, un motor de base de datos o un instalador de software puede mantener una lista de operaciones que se han realizado o se realizarán. Si uno de ellos falla, todos los demás se pueden revertir o descartar (lo que normalmente se denomina reversión ). Por ejemplo, si se deben actualizar dos tablas de bases de datos que hacen referencia entre sí y la segunda actualización falla, la transacción se puede revertir, de modo que la primera tabla no contenga ahora una referencia no válida.
magos
A menudo, un asistente presenta varias páginas de configuración para una única acción que ocurre sólo cuando el usuario hace clic en el botón "Finalizar" en la última página. En estos casos, una forma natural de separar el código de la interfaz de usuario del código de la aplicación es implementar el asistente mediante un objeto de comando. El objeto de comando se crea cuando se muestra el asistente por primera vez. Cada página del asistente almacena sus cambios de GUI en el objeto de comando, por lo que el objeto se completa a medida que el usuario avanza. "Finalizar" simplemente activa una llamada a ejecutar() . De esta forma, la clase de comando funcionará.

Terminología

La terminología utilizada para describir las implementaciones de patrones de comandos no es coherente y, por lo tanto, puede resultar confusa. Este es el resultado de la ambigüedad , el uso de sinónimos y las implementaciones que pueden oscurecer el patrón original al ir mucho más allá.

  1. Ambigüedad.
    1. El término comando es ambiguo. Por ejemplo, subir, subir puede referirse a un solo comando (subir) que debe ejecutarse dos veces, o puede referirse a dos comandos, cada uno de los cuales hace lo mismo (subir). Si el comando anterior se agrega dos veces a una pila de deshacer, ambos elementos de la pila hacen referencia a la misma instancia de comando. Esto puede ser apropiado cuando un comando siempre se puede deshacer de la misma manera (por ejemplo, bajar). Tanto el ejemplo de Gang of Four como el de Java que aparecen a continuación utilizan esta interpretación del término comando . Por otro lado, si los últimos comandos se agregan a una pila de deshacer, la pila hace referencia a dos objetos separados. Esto puede ser apropiado cuando cada objeto de la pila debe contener información que permita deshacer el comando. Por ejemplo, para deshacer un comando de eliminación de selección , el objeto puede contener una copia del texto eliminado para que pueda volver a insertarse, si el comando de eliminación de selección debe deshacerse. Tenga en cuenta que utilizar un objeto independiente para cada invocación de un comando también es un ejemplo del patrón de cadena de responsabilidad .
    2. El término ejecutar también es ambiguo. Puede referirse a ejecutar el código identificado por el método de ejecución del objeto de comando . Sin embargo, en Windows Presentation Foundation de Microsoft se considera que un comando se ha ejecutado cuando se ha invocado el método de ejecución del comando , pero eso no significa necesariamente que el código de la aplicación se haya ejecutado. Esto ocurre sólo después de un procesamiento adicional de eventos.
  2. Sinónimos y homónimos .
    1. Cliente, Fuente, Invocador : el botón, botón de la barra de herramientas o elemento del menú en el que se hace clic, la tecla de acceso directo presionada por el usuario.
    2. Objeto de comando, objeto de comando enrutado, objeto de acción : un objeto singleton (por ejemplo, solo hay un CopyCommandobjeto), que conoce las teclas de acceso directo, las imágenes de los botones, el texto del comando, etc., relacionados con el comando. Un objeto fuente o invocador llama al método de ejecución o ejecución del objeto Comando o Acción. El objeto Comando/Acción notifica a los objetos fuente/invocador apropiados cuando la disponibilidad de un comando/acción ha cambiado. Esto permite que los botones y elementos del menú queden inactivos (atenuados) cuando un comando/acción no se puede ejecutar/realizar.
    3. Receptor, objeto de destino : el objeto que está a punto de copiarse, pegarse, moverse, etc. El objeto receptor posee el método llamado por el método de ejecución del comando . El receptor suele ser también el objeto objetivo. Por ejemplo, si el objeto receptor es un cursor y se llama al método moveUp, entonces se esperaría que el cursor sea el objetivo de la moveUpacción. Por otro lado, si el código está definido por el propio objeto de comando, el objeto de destino será un objeto completamente diferente.
    4. Objeto de comando, argumentos de evento enrutados, objeto de evento : el objeto que se pasa desde el origen al objeto Comando/Acción, al objeto Destino y al código que realiza el trabajo. Cada clic en un botón o tecla de acceso directo da como resultado un nuevo objeto de comando/evento. Algunas implementaciones agregan más información al objeto de comando/evento a medida que se pasa de un objeto (p. ej. CopyCommand) a otro (p. ej., sección de documento). Otras implementaciones colocan objetos de comando/evento en otros objetos de evento (como un cuadro dentro de un cuadro más grande) a medida que se mueven a lo largo de la línea, para evitar conflictos de nombres. (Ver también patrón de cadena de responsabilidad ).
    5. Controlador, ExecutedRoutedEventHandlermétodo, función : el código real que copia, pega, mueve, etc. En algunas implementaciones, el código del controlador es parte del objeto de comando/acción. En otras implementaciones, el código es parte del objeto receptor/objetivo, y en otras implementaciones, el código del controlador se mantiene separado de los otros objetos.
    6. Administrador de comandos, Administrador de deshacer, Programador, Cola, Distribuidor, Invocador : un objeto que coloca objetos de comando/evento en una pila de deshacer o rehacer, o que retiene objetos de comando/evento hasta que otros objetos estén listos para actuar sobre ellos, o que enruta los objetos de comando/evento al código de controlador o receptor apropiado/objeto de destino.
  3. Implementaciones que van mucho más allá del patrón de comando original.
    1. Windows Presentation Foundation (WPF) de Microsoft introduce comandos enrutados, que combinan el patrón de comando con el procesamiento de eventos. Como resultado, el objeto de comando ya no contiene una referencia al objeto de destino ni una referencia al código de la aplicación. En cambio, invocar el comando de ejecución del objeto de comando da como resultado el llamado evento enrutado ejecutado que, durante el túnel o la difusión del evento, puede encontrar un llamado objeto vinculante que identifica el destino y el código de la aplicación, que se ejecuta en ese punto.

Ejemplo

Esta implementación de C++14 se basa en la implementación anterior a C++98 del libro.

#incluir <iostream> #incluir <memoria>  class Command { public : // declara una interfaz para ejecutar una operación. ejecución de vacío virtual () = 0 ; virtual ~ Comando () = predeterminado ; protegido : Comando () = predeterminado ; };               plantilla < typename Receiver > class SimpleCommand : public Command { // ConcreteCommand public : typedef void ( Receiver ::* Action )(); // define un enlace entre un objeto receptor y una acción. SimpleCommand ( std :: shared_ptr <Receptor> receptor_ , Acción acción_ ) : receptor ( receptor_ . get ( )) , acción ( acción_ ) { } SimpleCommand ( const SimpleCommand & ) = eliminar ; // regla de tres const SimpleCommand & operador = ( const SimpleCommand & ) = eliminar ; // implementa la ejecución invocando las operaciones correspondientes en Receiver. virtual void ejecutar () { ( receptor ->* acción )(); } privado : Receptor * receptor ; Acción acción ; };                                            class MyClass { // Receptor public : // sabe cómo realizar las operaciones asociadas con la realización de una solicitud. Cualquier clase puede actuar como Síndico. acción nula () { std :: cout << "MiClase::acción \n " ; } };           int main () { // Los punteros inteligentes evitan pérdidas de memoria. std :: share_ptr < MiClase > receptor = std :: make_shared < MiClase > (); // ... std :: Unique_ptr < Comando > comando = std :: make_unique < SimpleCommand < MiClase >> ( receptor , & MiClase :: acción ); // ... comando -> ejecutar (); }                

La salida del programa es

MiClase :: acción

Ver también

Historia

La primera mención publicada sobre el uso de una clase Command para implementar sistemas interactivos parece ser un artículo de 1985 de Henry Lieberman. [4] La primera descripción publicada de un mecanismo de deshacer y rehacer (de varios niveles), que utiliza una clase Command con métodos de ejecución y deshacer , y una lista histórica, parece ser la primera edición (1988) del libro Object de Bertrand Meyer . Construcción de software orientada a , [5] sección 12.2.

Referencias

  1. ^ Erich Gamma; Richard Helm; Ralph Johnson; John Vlissides (1994). Patrones de diseño: elementos de software reutilizable orientado a objetos . Addison Wesley. págs. 233 y siguientes. ISBN 0-201-63361-2.
  2. ^ "El patrón de diseño del comando: problema, solución y aplicabilidad". w3sDesign.com . Archivado desde el original el 23 de septiembre de 2020 . Consultado el 12 de agosto de 2017 .
  3. ^ "El patrón de diseño Command: estructura y colaboración". w3sDesign.com . Consultado el 12 de agosto de 2017 .[ enlace muerto ]
  4. ^ Liberman, Henry (1985). "Hay más en los sistemas de menús de lo que se ve en la pantalla". Gráficos por computadora ACM SIGGRAPH . 19 (3): 181–189. doi :10.1145/325165.325235.
  5. ^ Meyer, Bertrand (1988). Construcción de software orientado a objetos (1ª ed.). Prentice Hall.

enlaces externos