2012-08-28 13 views
11

Command pattern se puede utilizar para implementar Transactional behavior (y Undo).
Pero no pude encontrar un ejemplo de estos en Google. Solo pude encontrar algunos ejemplos triviales de una lámpara que es switched on o off.
¿Dónde puedo encontrar un ejemplo de codificación (preferiblemente en Java) de este/estos comportamientos implementados usando el Command Pattern?Ejemplo del mundo real de la aplicación del patrón de comando

Respuesta

11

En uno de nuestros proyectos, tenemos el siguiente requisito:

  1. crear un registro en la base de datos.
  2. Llama a un servicio para actualizar un registro relacionado.
  3. Llamar a otro servicio para registrar un ticket.

Para realizar esto de forma transaccional, cada operación se implementa como un comando con la operación de deshacer. Al final de cada paso, el comando se coloca en una pila. Si la operación falla en algún momento, extraemos los comandos de la pila y llamamos a la operación deshacer en cada uno de los comandos que aparecieron. La operación de deshacer de cada paso se define en esa implementación de comando para revertir el comando anterior.execute().

Espero que esto ayude.

+0

No estoy seguro de seguir. Una transacción se retrotrae. No está compuesta de operaciones de deshacer. ¿Cómo implementó la parte atómica con el patrón de comando? – Jim

+0

En una transacción de nivel de base de datos, cada operación es un comando con operaciones de deshacer y rehacer. Tras la reversión, el DBMS llamará a la operación de deshacer para revertir los cambios realizados a la copia del DB que tenía. Estamos simulando lo mismo en una transacción distribuida que abarca todos los sistemas. ¿Tiene esto sentido ahora? – Vikdor

+0

'revertir los cambios realizados en la copia del DB que contenía'. ¿Entonces el comando se aplica primero a una copia de los datos y no a los datos reales? Pensé que se aplicaba directamente a los datos y es por eso que necesita' deshacer'. Su descripción es clara pero necesito un poco más de detalles de bajo nivel si es posible para ver la imagen completa – Jim

2
public final class Ping implements Callable<Boolean> { 

    private final InetAddress peer; 

    public Ping(final InetAddress peer) { 
    this.peer = peer; 
    } 

    public Boolean call() { 
    /* do the ping */ 
    ... 
    } 
} 
... 
final Future<Boolean> result 
    = executorService.submit(new Ping(InetAddress.getByName("google.com"))); 
System.out.println("google.com is " + (result.get() ? "UP" : "DOWN")); 
+5

¿Qué es este ejemplo? – Jim

+0

@Jim el artículo de Wikipedia sobre el patrón menciona explícitamente lo siguiente ... "* Una clase de agrupación de subprocesos típica de propósito general podría tener un método público de 'addTask' que agregue un elemento de trabajo a una cola interna de tareas esperando a realizarse ... Los elementos en 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 aunque la clase del grupo de subprocesos se escribió sin ningún conocimiento de las tareas específicas para las que se usaría. * " – oldrinb

+0

@Jim este es un ejemplo en Java excepto que se usa' Callable' en lugar de 'Runnable' junto con un [' ExecutorService'] (http: // docs. oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html). Un ejemplo similar se puede ver en la discusión sobre el artículo de Wikipedia en sí [aquí] (http://en.wikipedia.org/wiki/Talk%3ACommand_pattern#Python_examples). – oldrinb

1

Los patrones de comando se utilizan en muchos lugares.

  1. Por supuesto, lo que ves en todas partes es un ejemplo muy trivial de Implementación de GUI, switches. También se usa extensivamente en el desarrollo de juegos. Con este patrón, el usuario puede configurar sus botones en la pantalla también.
  2. También se usa en Redes, si se debe pasar un comando al otro extremo.
  3. Cuando los programadores desean almacenar todos los comandos ejecutados por el usuario, p. a veces un juego te permite reproducir todo el nivel.
  4. Se utiliza para implementar devoluciones de llamada.

Aquí hay un sitio que proporciona un ejemplo del patrón de comando utilizado para la devolución de llamada. http://www.javaworld.com/article/2077569/core-java/java-tip-68--learn-how-to-implement-the-command-pattern-in-java.html?page=2

  1. Aquí hay otro enlace que muestra el patrón de comando con la base de datos. El código está en C#. http://www.codeproject.com/Articles/154606/Command-Pattern-at-Work-in-a-Database-Application
0

You have to define undo(), redo() operations along with execute() in Command interface itself.

ejemplo:

interface ChangeI { 
    enum State{ READY, DONE, UNDONE, STUCK } ; 
    State getState() ; 

    void execute() ;  
    void undo() ;  
    void redo() ; 
} 

definir un Estado en su clase ConcreteCommand. Dependiendo del estado actual después del método execute(), debe decidir si se debe agregar el comando a Undo Stack o Redo Stack y tomar las decisiones correspondientes.

abstract class AbstractChange implements ChangeI { 
    State state = State.READY ; 

    public State getState() { return state ; } 

    public void execute() { 
     assert state == State.READY ; 
     try { doHook() ; state = State.DONE ; } 
     catch(Failure e) { state = State.STUCK ; } 
     catch(Throwable e) { assert false ; } 
    } 

    public void undo() { 
     assert state == State.DONE ; } 
     try { undoHook() ; state = State.UNDONE ; } 
     catch(Failure e) { state = State.STUCK ; } 
     catch(Throwable e) { assert false ; } 
    } 

    public void redo() { 
     assert state == State.UNDONE ; 
     try { redoHook() ; state = State.DONE ; } 
     catch(Failure e) { state = State.STUCK ; } 
     catch(Throwable e) { assert false ; } 
    } 

    protected abstract void doHook() throws Failure ; 

    protected abstract void undoHook() throws Failure ; 

    protected void redoHook() throws Failure { doHook() ;} ; 
} 

Tener un vistazo a este artículo undo-redo de comandos para una mejor comprensión.

Cuestiones relacionadas