Patrones de diseño de comportamiento: Command

Intensión del patrón

  • Encapsular una solicitud como un objeto, lo que permite parametrizar clientes con diferentes solicitudes, cola o registro de solicitudes, y soportar operaciones que se pueden deshacer.
  • Promover la "invocación de un método en un objeto" a ser un objeto "completo".
  • Un callback orientado a objeto.

Ejemplo de problema

Se necesita emitir peticiones a los objetos sin saber nada de la operación que se solicita o el receptor de la solicitud.

Discusión

Command desacopla el objeto que invoca la operación del único que conoce cómo realizarla. Para lograr esta separación, el diseñador crea una clase base abstracta que mapea un receptor (un objeto) con una acción (un puntero a una función de clase). La clase base contiene un método Ejecutar() que simplemente llama a la acción en el receptor.
Todos los cliente de objetos Command tratan cada objeto como una "caja negra" mediante la simple invocación del método virtual  Ejecutar() del objeto siempre que el cliente requiera el 2servicio" del objeto.
Una clase Command tiene un subconjunto de los siguientes: un objeto, un método para ser aplicado al objeto y los argumentos para ser pasados cuando el método es aplicado. El método  Ejecutar() causa que las piezas encajen.
Las secuencias de objetos Command pueden ser ensambladas en comandos compuestos (o macros).

Estructura

El cliente que crea un Command no es el mismo cliente que lo ejecuta. Esta separación proporciona flexibilidad en el tiempo y secuencia de los comandos. Transformado comandos en objetos produce que ellos puedan ser pasados, separados en etapas, compartidos, cargados en un tabla y por otro lado, instrumentados y manipulados como cualquier otro objeto.


Se puede considerar a los objetos Command como "tokens" que son creados por un cliente que conoce qué necesita hacerse y pasado a otro cliente que tiene los recursos necesarios para hacerlo.

Ejemplo

El patrón Command permite a las solicitudes ser encapsuladas como objetos, logrando así permitirle a los clientes parametrizar con diferentes solicitudes. El "pedido" en un restaurante es un ejemplo de patrón Command. El mozo o mesera toma la orden (pedido) del comensal y lo encapsula al escribirla en su anotador. La orden es entonces derivada al chef para que la procese. Se debe tener en cuenta que el anotador no depende de ningún menú, por lo que se puede soportar cualquier orden para cocinar muchos diferentes items.


Check list

  1. Definir una interfaz Command con la firma de un método similar a Ejecutar().
  2. Crear una o más clases implementándola que encapsule algún subconjunto de los siguientes: un objeto "receptor", el método a invocar y los argumentos a pasar.
  3. Instanciar un objeto Command para cada ejecución de solicitud diferida.
  4. Pasar el objeto Command desde el creador (Emisor) hacia quien es llamado (Receptor).
  5. El receptor decide cuando invocar al método Ejecutar().

Reglas de oro

  • Chain of ResponsabilityCommandMediator Observer indican cómo se puede desacoplar a los emisores de los receptores, pero con diferentes ventajas y desventajas. Command normalmente especifica una conexión Emisor-Receptor con una subclase.
  • Chain of Responsability puede usar Command para representar solicitudes como objetos.
  • Command y Memento actúan como tokens mágicos que se pasan por alto y son invocados más tarde. En Command, el token representa una solicitud; en Memento, representa el estado interno de un objeto en un momento en particular. El polimorfismo es importante para Command, pero no para el patróm Memento dado que su interfaz es tan acotada que un memento sólo puede ser pasado como valor.
  • Command puede usar a Memento para mantener el estado requerido una operación "deshacer".
  • MacroCommand puede ser implementado con Composite.
  • Un Command que debe ser copiado antes de ser puesto en una lista histórica, actúa como un Prototype.

Ejemplo de código en C#

using System;

class MainApp
{
  static void Main()
  {
    // Create receiver, command, and invoker 
    Receiver receiver = new Receiver();
    Command command = new ConcreteCommand(receiver);
    Invoker invoker = new Invoker();

    // Set and execute command 
    invoker.SetCommand(command);
    invoker.ExecuteCommand();

    // Wait for user 
    Console.Read();
  }
}

// "Command" 
abstract class Command 
{
  protected Receiver receiver;

  // Constructor 
  public Command(Receiver receiver)
  {
    this.receiver = receiver;
  }

  public abstract void Execute();
}

// "ConcreteCommand" 
class ConcreteCommand : Command
{
  // Constructor 
  public ConcreteCommand(Receiver receiver) : 
    base(receiver) 
  {  
  }

  public override void Execute()
  {
    receiver.Action();
  }
}

// "Receiver" 
class Receiver 
{
  public void Action()
  {
    Console.WriteLine("Called Receiver.Action()");
  }
}

// "Invoker" 
class Invoker 
{
  private Command command;

  public void SetCommand(Command command)
  {
    this.command = command;
  }

  public void ExecuteCommand()
  {
    command.Execute();
  }    
}

0 comentarios:

Publicar un comentario

Muchas gracias por leer el post y comentarlo.

 
Copyright 2009 Programación SOLIDa
BloggerTheme by BloggerThemes | Design by 9thsphere