Uso del patrón de diseño de comando

¿Alguien puede explicar con un simple ejemplo de Command Pattern? Me refiero en internet, pero me confundí.

    public interface Command { public void execute(); } 

    En su mayor parte, los comandos son inmutables y contienen instrucciones que encapsulan una sola acción que se ejecuta bajo demanda. También puede tener un RuntimeCommand que acepte instrucciones durante la ejecución, pero esto profundiza más en la estrategia o en los patrones de decorador dependiendo de las implementaciones.

    En mi opinión, creo que es muy importante prestar atención al contexto inmutable de un comando, de lo contrario el comando se convierte en una sugerencia. Por ejemplo:

     public final class StopServerCommand implements Command { private final Server server; public StopServerCommand(Server server) { this.server = server; } public void execute() { if(server.isRunning()) server.stop(); } } public class Application { //... public void someMethod() { stopButton.addActionListener(new ActionListener() { public void actionPerformed(Event e) { stopCommand.execute(); } }); } } 

    Personalmente, realmente no me gustan los comandos. En mi propia experiencia, solo funcionan bien para las devoluciones de marcos.

    Si ayuda, piense en un comando en un sentido metafórico; un soldado entrenado recibe un comando de su comandante y, a petición, el soldado ejecuta este comando.

    Aquí hay otro ejemplo que puede usar para comprender cómo funciona el patrón de comando, usando escenarios de la vida real: ¡No puede viajar de un lugar a otro por avión sin usar el patrón de comando!

    Si usted es un viajero frecuente, lo único que le importa como cliente es viajar desde donde se encuentra a otro. no le importa cómo el piloto volará el avión o qué línea aérea estará disponible … realmente no puede predecir eso. todo lo que desea es obtener el puerto aéreo y decirles que lo lleven a su destino.

    ¡Pero si haces eso, se reirán de tu orden a las autoridades aeroportuarias! necesitan que suministres un objeto de comando, que es tu ticket. Por mucho que no le importe qué aerolínea o qué tipo de avión, cuando esté listo para volar, debe proporcionar un objeto de comando de ticket. El invocador, que es el funcionario del aeropuerto, necesita verificar tu comando (ticket) para poder validarlo, deshacerlo si es falso, rehacerlo si se equivocaron (sin tener que pasar por el proceso de reserva) .

    En resumen, quieren tener el control completo de su comando (ticket) antes de decidir si invocar o ejecutar su comando, lo que le permite a la línea aérea (el receptor) ejecutar (ponerlo en un avión y llevarlo a su destino).

    Tenga en cuenta que su orden (su boleto) ya tiene la información del receptor (línea aérea) sin la cual los funcionarios del aeropuerto ni siquiera comenzarán a procesar su boleto en primer lugar.

    Las autoridades del aeropuerto incluso podrían tener un montón de boletos en los que están trabajando. pueden optar por retrasar mi boleto y permitir que alguien que venga detrás de mí lo haga (invocar el boleto de otra persona antes que el mío)

    Aquí está el código:

      [TestClass] public class Client { [TestMethod] public void MyFlight_UsingCommandPattern() { var canadianAirline = new Airline(); AirlineTicket_Command myTicket = new MyAirLineTicket(canadianAirline); var airportOfficials = new AirportOfficials_Invoker(myTicket); airportOfficials.ProcessPasengerTicket_And_AllowPassengerToFly_Execute(); //assert not implemented } } public class AirportOfficials_Invoker { private AirlineTicket_Command PassengerTicket { set; get; } public AirportOfficials_Invoker(AirlineTicket_Command passengerTicket) { throw new NotImplementedException(); } public void ProcessPasengerTicket_And_AllowPassengerToFly_Execute() { PassengerTicket.Execute(); } } public abstract class AirlineTicket_Command { protected Airline Airline { set; get; } protected AirlineTicket_Command(Airline airline) { Airline = airline; } public abstract void Execute(); } public class MyAirLineTicket : AirlineTicket_Command { public MyAirLineTicket(Airline airline) : base(airline) { } public override void Execute() { Airline.FlyPassenger_Action(); } } public class Airline { public void FlyPassenger_Action() { //this will contain all those stuffs of getting on the plane and flying you to your destination } } 

    Puede pensar en el flujo de trabajo del patrón Command de la siguiente manera.

    Llamadas de cliente Invoker => Llamadas de Invoker ConcreteCommand => ConcreteCommand llama al método Receiver , que implementa el método abstracto Command .

    Diagtwig UML del artículo de dofactory :

    enter image description here

    Principales características:

    1. Command declara una interfaz para todos los comandos, proporcionando un método simple execute () que le pide al destinatario del comando que realice una operación.

    2. El Receptor tiene el conocimiento de qué hacer para llevar a cabo la solicitud.

    3. El Invoker tiene un comando y puede hacer que el comando ejecute una solicitud llamando al método de ejecución.

    4. El Cliente crea ConcreteCommands y establece un Receptor para el comando.

    5. ConcreteCommand define un enlace entre la acción y el receptor.

    6. Cuando las llamadas de Invoker se ejecutan, ConcreteCommand ejecutará una o más acciones en el Receptor.

    Fragmento de código:

     interface Command { void execute(); } interface Receiver { public void switchOn(); } class OnCommand implements Command{ private Receiver receiver; public OnCommand(Receiver receiver){ this.receiver = receiver; } public void execute(){ receiver.switchOn(); } } class Invoker { private Command command; public Invoker(Command command){ this.command = command; } public void execute(){ this.command.execute(); } } class TV implements Receiver{ public void switchOn(){ System.out.println("Switch on from TV"); } } class DVDPlayer implements Receiver{ public void switchOn(){ System.out.println("Switch on from DVDPlayer"); } } public class CommandDemoEx{ public static void main(String args[]){ // On command for TV with same invoker Receiver receiver = new TV(); Command onCommand = new OnCommand(receiver); Invoker invoker = new Invoker(onCommand); invoker.execute(); // On command for DVDPlayer with same invoker receiver = new DVDPlayer(); onCommand = new OnCommand(receiver); invoker = new Invoker(onCommand); invoker.execute(); } } 

    salida:

     Switch on from TV Switch on from DVDPlayer 

    Explicación:

    En este ejemplo,

    1. La interfaz de comando define el método execute() .
    2. OnCommand es ConcreteCommand , que implementa el método execute() .
    3. Receiver es una interfaz y los implementadores deben proporcionar implementación para los métodos.
    4. TV y DVDPlayer son dos tipos de receptores , que se pasan a ConcreteCommand como OnCommand.
    5. Invoker contiene Comando . Es la clave para desconectar el remitente de Receiver .
    6. Invoker recibe OnCommand -> que llama a Receiver (TV) para ejecutar este comando.

    Al usar Invoker, puede encender TV y DVDPlayer. Si extiende este progtwig, apaga tanto TV como DVDPlayer.

    Puedes usar el patrón Command para

    1. Desacoplar el emisor y el receptor del comando

    2. Implementar el mecanismo de callback

    3. Implementar la funcionalidad de deshacer y rehacer

    4. Mantener un historial de comandos

    Echa un vistazo a este dzone, journaldev y artículos de Wikipedia .

    El código fuente como página de Wikipedia es simple, más limpio y se explica por sí mismo.

    Puede implementar Deshacer y Rehacer si sigue los pasos que se indican en este artículo

    Mi requerimiento es realizar una secuencia de tareas (que pueden reutilizarse en varios Usos) cada una con su propio flujo de excepción. La implementación del patrón de comando encontrado es lógica aquí.

    Estoy tratando de hacer que cada acción ejecutada por el comando (ya sea flujo normal / alternativo) también pueda ser un manejador de excepciones. Sin embargo, si el comando está registrado con otro controlador, entonces debería usarse. Cualquier sugerencia para mejora / corrección es bienvenida.

     public interface Command { Result run() throws Exception; Command onException(ExceptionHandler handler); } public class Result { } public interface ExceptionHandler { void handleException(Exception e); } public interface Action { Result execute() throws Exception; } public class BasicCommand implements Command { private Action action; private ExceptionHandler handler; public BasicCommand(Action action) { if (action == null) { throw new IllegalArgumentException("Action must not be null."); } this.action = action; this.handler = (ExceptionHandler) this.action; } @Override public Command onException(ExceptionHandler handler) { if (handler != null) { this.handler = handler; } return this; } public Result run() throws Exception { Result result = null; try { result = action.execute(); } catch (Exception e) { handler.handleException(e); } return result; } 

    }

     public class BasicAction implements Action, ExceptionHandler { private Object[] params; public BasicAction(Object... params) { this.params = params; } @Override public Result execute() throws Exception { // TODO Auto-generated method stub return null; } @Override public void handleException(Exception e) { // TODO exception translation: prepare unchecked application. exception and throw.. } } public class Main { public static void main(String[] args) throws Exception { int param1 = 10; String param2 = "hello"; // command will use the action itself as an exception handler Result result = new BasicCommand(new BasicAction(param1, param2)).run(); ExceptionHandler myHandler = new ExceptionHandler(){ @Override public void handleException(Exception e) { System.out.println("handled by external handler"); } }; // command with an exception handler passed from outside. Result result2 = new BasicCommand(new BasicAction(param1, param2)).onException(myHandler).run(); } } 

    Command Design Patterns desacopla el invocador del servicio y el proveedor del servicio. En el escenario general, digamos por ejemplo, si el Object A quiere el servicio del Object B , invocará directamente a B.requiredService() . Por lo tanto, A conoce el patrón B. En Comando, este acoplamiento se elimina. Aquí, hay un objeto intermedio conocido como Command , que entra en la imagen. Por lo tanto, A trata con el objeto Command y el objeto Command trata con el objeto real B Este enfoque tiene varias aplicaciones, como el diseño de aplicaciones, que son:

    • Acepta comandos como solicitudes.
    • Deshaciendo solicitudes.
    • Solicitudes de solicitudes.
    • Creando macros.
    • Creando Task Executors y Task Managers.

    Para obtener más información sobre Command Pattern Pattern, recomendaré https://en.wikipedia.org/wiki/Command_pattern . Para todos los demás patrones de diseño, consulte https://www.u-cursos.cl/usuario/…/mi_blog/r/head_first_design_patterns.pdf