¿Cuánta lógica se puede poner en un comando? O de otra manera: ¿para qué tipo de lógica es el patrón de comando?

8

He estado usando el patrón de comando durante bastante tiempo, pero nunca estoy realmente seguro de cuánta lógica puedo poner en el método Execute .

Mi implementación actual del patrón de comando es similar a esto:

public abstract class Command
{
    public static event EventHandler Completed = delegate { };        

    public bool Success { get; private set; }

    public Exception Exception {get; private set; }

    public abstract bool Execute();

    protected bool OnCompleted(bool success, Exception ex = null)
    {       
        Success = success;
        Exception = ex;
        Completed(this, EventArgs.Empty)
        return success;
    }
}

y estas son las preguntas que me hago (y practico con mis comandos):

  1. ¿Está bien mostrar cuadros de mensajes o cuadros de diálogo de abrir archivos, etc.?
  2. ¿Está bien establecer propiedades de cualquier objeto?
  3. ¿Puede un comando contener lógica de negocios?
  4. ¿Puede un comando modificar los controles de GUI de alguna manera?
  5. ¿A qué comandos de capa pertenecen? Ver o capa de datos? ¿Puedo tener comandos en ambas capas?
  6. ¿Puede un comando hacer todo lo que anteriormente estaba en button1_Click ?
  7. ¿Debe un comando por unidad verificable?
  8. ¿Se puede ver un comando como un usuario que hace uso de las API y que crea la última capa de una aplicación y también el último recurso para capturar excepciones?
  9. ¿Los comandos pueden ejecutarse también por código (el comando llama a api, api se ejecuta y finalmente otra api llama a un comando) o solo el usuario puede invocarlo y las API no deben saber sobre su existencia?
  10. ¿Hay un lugar para los comandos en MVC o MVVC o cualquier otro patrón de diseño con un controlador? Parecen ser mutuamente excluyentes. ¿Qué es preferible?

Hay muchos tutoriales que muestran cómo implementar el patrón de comando, pero ninguno realmente discute cómo aplicarlo en una aplicación real.

    
pregunta t3chb0t 21.01.2015 - 12:28

2 respuestas

7

Patrón de comando se usa generalmente para desacoplar QUÉ de QUIÉN, y QUÉ de CUÁNDO. Este es el beneficio de tener una interfaz simple tan simple como:

public abstract class Command {
    public abstract void execute();
}

Imaginemos que tienes una clase EngineOnCommand . Puede pasar este comando a otros objetos que acepten instancias de comando. Entonces, esto significa que la clase que recibe este EngineOnCommand, también podría recibir un comando diferente para ser ejecutado por él y nunca debería saberlo. Esto significa que se ha desacoplado QUÉ de OMS .

Ahora, el segundo caso para el patrón de comando es desacoplar QUÉ de CUANDO . Imaginemos que desea crear un sistema en el que las acciones en la base de datos solo se ejecuten de noche, pero siguiendo la secuencia en la que se solicitaron. Con una cola de comandos en la que puede ejecutar uno por uno, podría haberlo logrado. La idea es que la invocación del comando en realidad solo activa una puesta en cola del comando en una lista que se ejecutará más adelante.

Espero que mis ejemplos anteriores ayuden a entender cuál es la idea del patrón. Ahora intentaré responder algunas de sus preguntas utilizando la base anterior.

  

¿Puede un comando contener lógica de negocios?

sí, creo que debería contenerlo. Lo contendrá de forma desacoplada de WHO y WHEN.

  

¿Puede un comando modificar los controles de GUI de alguna manera?

Esto significa que lo está acoplando a la GUI. Esto significa que no se está utilizando para la intención de desacoplar QUÉ de la OMS. Lo ideal es que el comando no sepa quién lo invoca, si se trata de una GUI o de una funcionalidad por lotes.

  

¿Debe un comando por unidad verificable?

No debería, debe ser comprobable por unidad . Todo el código debe ser verificable por unidad, pero idealmente todos los comandos deben ser verificables por unidad.

Lo siento por no responder a todas sus preguntas, pero creo que debería consultar el libro GOF . Contiene algunos buenos ejemplos.

    
respondido por el pietromenna 21.01.2015 - 14:38
2

La mayor parte del beneficio de los comandos es que facilitan deshacer una acción, rehacer una acción, realizar una acción en múltiples lugares (a través de una conexión de red), o realizarla en una fecha posterior, y así sucesivamente.

Con eso en mente:

  1. Probablemente no. Es difícil imaginar una situación en la que "deshacer" un cuadro de diálogo tenga sentido, y este es el tipo de cosas que preferiría poner en el código de la interfaz de usuario.

  2. Siempre que se pueda acceder a ese objeto desde cualquier lugar que quiera ejecutar el comando, por supuesto que está bien cambiar sus propiedades.

  3. Absolutamente. Esto se relaciona con si su modelo debe "contener" la lógica empresarial; en realidad se considera un anti-patrón ("modelo de dominio anémico") por tener muy poca lógica de negocios allí.

  4. Si los controles de la GUI son parte de su modelo, absolutamente. Si no, es cuestionable.

  5. Definitivamente no es la vista. Se debe informar a la vista que los datos o el modelo han cambiado y reaccionar en consecuencia, pero el cambio real debe tener lugar en los datos o el modelo.

  6. En principio, probablemente sí. Ser capaz de deshacer comandos es una de las mejores cosas acerca del patrón.

  7. La función de ejecución () del comando definitivamente debe ser probada por una unidad. Nuevamente, si los comandos están vinculados a un modelo de algún tipo, están entre las partes más fáciles de probar de una aplicación.

  8. No estoy seguro de lo que quieres decir, pero:

    • Es perfectamente correcto que una API externa utilice comandos como entrada o salida. Suponiendo que los valides, por supuesto.
    • "última capa" suena como una vista para mí. En MVC, los comandos probablemente deberían ser generados por el controlador y manejados por el modelo, por lo que sería sensato decir que la vista está construida "por encima" del material del comando, si eso es lo que buscaba.
    • En cuanto a las excepciones, probablemente no. En MVC, esperaría que el controlador fuera la única que detectara las excepciones y las convirtiera en el tipo correcto de cuadro de diálogo. No el modelo / comandos.
  9. Absolutamente. La mayoría de los beneficios de los comandos son imposibles de implementar si el código nunca los ejecuta.

  10. Probablemente sea obvio a estas alturas, pero no las veo como mutuamente excluyentes. En mi equipo en el trabajo, el controlador traduce los eventos generados por el usuario en comandos, el modelo recibe y ejecuta los comandos (y guarda los comandos de "deshacer" en algún lugar), y cuando se hace, el controlador le dice a la vista que se actualice basándose en el nuevo modelo . Los comandos también se envían a través de la red a cualquier copia del modelo que ven otros usuarios, por lo que también lo ven. Funciona brillantemente.

Y la pregunta del título: ¿Cuánta lógica poner en un comando? Yo no pondría ningún mínimo o máximo en él. Lo que diría es que es una muy buena idea implementar comandos más complejos utilizando una serie de comandos más simples, y refactorizar los comandos de la misma manera que refactorizaría las funciones.

    
respondido por el Ixrec 21.01.2015 - 14:27

Lea otras preguntas en las etiquetas