Loading AI tools
De Wikipedia, la enciclopedia libre
En programación orientada a objetos, Command es un patrón de diseño.
Este patrón permite solicitar una operación a un objeto sin conocer realmente el contenido de esta operación, ni el receptor real de la misma. Para ello se encapsula la petición como un objeto, con lo que además facilita la parametrización de los métodos.
La terminología usada para describir la implementación del patrón orden (command pattern) no es consistente y puede por tanto ser confusa. Esto resulta de la ambigüedad, el uso de sinónimos e implementaciones que puede oscurecer el patrón original por ir más allá de él.
Considérese un "simple" interruptor. En este ejemplo configuramos el interruptor con dos órdenes: encender la luz y apagar la luz. Después, se va a hacer una pequeña refactorización para añadir el beneficio al usar las abstracciones correctas en los Command para hacer que el interruptor puede ser usado en cualquier dispositivo no solo con una luz. Como se va a ver en el siguiente ejemplo, el interruptor enciende y apaga la luz, pero el constructor del interruptor es capaz de aceptar cualquier subclase de Orden para sus dos parámetros y con una fácil abstracción, el último ejemplo modelará el interruptor para funcionar sobre cualquier dispositivo capaz de encenderse o apagarse como un motor, por ejemplo.
/* The Invoker class */
public class Switch {
private Command flipUpCommand;
private Command flipDownCommand;
public Switch(Command flipUpCmd, Command flipDownCmd) {
this.flipUpCommand = flipUpCmd;
this.flipDownCommand = flipDownCmd;
}
public void flipUp() {
flipUpCommand.execute();
}
public void flipDown() {
flipDownCommand.execute();
}
}
/* The Receiver class */
public class Light {
public Light() { }
public void turnOn() {
System.out.println("The light is on");
}
public void turnOff() {
System.out.println("The light is off");
}
}
/* The Command interface */
public interface Command {
void execute();
}
/* The Command for turning the light on in North America, or turning the light off in most other places */
public class FlipUpCommand implements Command {
private Light theLight;
public FlipUpCommand(Light light) {
this.theLight=light;
}
public void execute(){
theLight.turnOn();
}
}
/* The Command for turning the light off in North America, or turning the light on in most other places */
public class FlipDownCommand implements Command {
private Light theLight;
public FlipDownCommand(Light light) {
this.theLight=light;
}
public void execute() {
theLight.turnOff();
}
}
/* The test class or client */
public class PressSwitch {
public static void main(String[] args){
// Check number of arguments
if (args.length != 1) {
System.err.println("Argument \"ON\" or \"OFF\" is required.");
System.exit(-1);
}
Light lamp = new Light();
Command switchUp = new FlipUpCommand(lamp);
Command switchDown = new FlipDownCommand(lamp);
// See criticism of this model above:
// The switch itself may not be aware of the specific receiver details (the lamp)
Switch mySwitch = new Switch(switchUp, switchDown);
switch (args[0]) {
case "ON":
mySwitch.flipUp();
break;
case "OFF":
mySwitch.flipDown();
break;
default:
System.err.println("Argument \"ON\" or \"OFF\" is required.");
System.exit(-1);
}
}
}
Una crítica de la aplicación de ejemplo es que no modeliza verdaderamente un circuito eléctrico. Un interruptor eléctrico es tonto. Un verdadero interruptor binario solo conoce si está en una posición u otra. Nótese que el ejemplo es perfectamente válido para modelar un interruptor que solo entiende/funciona con lámparas pero el uso del patrón Command nos da la suficiente abstracción para que no se limite solo a eso.
Así, una primera solución para un modelo más general sería:
Así, la posible solución que sigue el planteamiento del patrón de una forma más simple sería proveer la abstracción para que tanto los comandos concretos (como indirectamente el interruptor) manejara elementos capaces de encenderse/apagarse. Esto se consigue con estos simples cambios en el código original del ejemplo:
/* An interface that defines actions that the receiver can perform */
public interface ISwitchable {
void turnOn();
void turnOff();
}
/* The Receiver class */
public class Light implements ISwitchable {
public Light() { }
public void turnOn() {
System.out.println("The light is on");
}
public void turnOff() {
System.out.println("The light is off");
}
}
/* The Command for turning the light on in North America, or turning the light off in most other places */
public class FlipUpCommand implements Command {
private final ISwitchable switchableReceiver;
public FlipUpCommand(ISwitchable switchableReceiver) {
this.switchableReceiver = switchableReceiver;
}
public void execute(){
switchableReceiver.turnOn();
}
}
/* The Command for turning the light off in North America, or turning the light on in most other places */
public class FlipDownCommand implements Command {
private final ISwitchable switchableReceiver;
public FlipDownCommand(ISwitchable switchableReceiver) {
this.switchableReceiver = switchableReceiver;
}
public void execute() {
switchableReceiver.turnOff();
}
}
Ninguno de los otros participantes: Command y Client (CommandManager) tiene que cambiarse.
Clase que ofrece una interfaz para la ejecución de órdenes. Define los métodos do y undo que se implementarán en cada clase concreta.
Clase que implementa una orden concreta y sus métodos do y undo. Su constructor debe inicializar los parámetros de la orden.
Clase que instancia las órdenes, puede a su vez ejecutarlas inmediatamente (llamando a do) o dejar que el CommandManager lo haga.
Responsable de gestionar una colección de objetos orden creadas por el Invoker. llamará a los métodos do y unDo. Gestionará su secuenciación y reordenación (sobre la base de prioridades por ejemplo).
Las clases Button y MenuItem de Java facilitan la utilización de este patrón, declaran los métodos getActionCommand y setActionCommand para dar nombres a las acciones realizadas por los objetos, facilitándose una correspondencia entre ambos.
Ofrece una forma alternativa de llamar a los órdenes además del uso del command manager.
Se puede implementar un pequeño Intérprete mediante clases Command.
Puede servir para implementar la lógica de Deshacer de forma un tanto automática o a alto nivel.
Permite realizar agrupaciones de órdenes de forma similar a una macro.
Hay quien lo utiliza para implementar la copia de la orden al histórico de órdenes.
Puede mantener el estado que requiere el comando para deshacer su efecto.
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.