Command Pattern en Java y la gestion de tareas

El concepto de Command Pattern o patron comando es uno de los más conocidos en el mundo de la programación. ¿Para qué sirve el patrón comando y que situaciones resuelve?. En programación nos podemos encontrar en muchas situaciones en las que tenemos que gestionar tareas que reciben algún tipo de objeto como parámetro.

java command pattern

Una vez recibido este objeto deberemos procesarle. En principio es una tarea que parece muy sencilla y nos bastaría con tener una clase que implemente las diferentes tareas para el objeto .Vamos a ver un ejemplo concreto que nos ayude a clarificar. Supongamos que disponemos de una clase Producto.


package com.arquitecturajava;

public class Producto {

	private int id;
	private String nombre;
	private double precio;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getNombre() {
		return nombre;
	}
	public void setNombre(String nombre) {
		this.nombre = nombre;
	}
	public double getPrecio() {
		return precio;
	}
	public void setPrecio(double precio) {
		this.precio = precio;
	}
}


Deberemos realizar varias tareas :

  • ValidarProducto
  • EnviarPorCorreo
  • Imprimir

Estamos ante una situación muy sencilla, nos es suficiente con crear una clase que disponga de tres métodos que que encarguen cada uno de una operación:



package com.arquitecturajava;

public class GestorProductos {

	public void validarProducto(Producto producto) {

		if (producto.getPrecio() < 100) {

			System.out.println("producto valido");
		} else {

			System.out.println("producto invalido");
		}
	}

	public void imprimirProducto(Producto producto) {
		
		System.out.println(producto.getNombre());
		System.out.println(producto.getId());
		System.out.println(producto.getPrecio());
	}
	
	public void enviarPorCorreo(Producto producto) {
		
		System.out.println(producto.getNombre() +"enviado por correo") ;
	}
}

 

Sin Java Command Pattern

Los problemas surgen cuando no hay solo tres tareas que ejecutar , sino que el número de tareas crece de forma exponencial .

java command pattern

Esto en principio nos puede resultar raro , pero no hay nada mas que mirar nuestro programa y darnos cuentas que podemos ejecutar muchas tareas y muy diferentes sobre el concepto de producto . Una solución sencilla pasaría por construir más clases que almacenen los diferentes métodos.

java command pattern tareas

 

Sin embargo no siempre es la mejor solución ya que genera un fuerte acoplamiento entre el cliente y los diferentes componentes. Por otro lado no siempre es sencillo decidir que tareas van en cada clase ya que con el paso del tiempo las tareas y la relación entre ellas varia en un negocio.

Java Command Pattern  una solución elegante

Para solventar este problema vamos a  construir un ejemplo usando Java Command Pattern . Este patrón se encarga de definir el concepto abstracto de Tarea y  de construir varias clases que lo implementen

 

java command pattern jerarquia

 


package com.arquitecturajava;

public interface TareaProducto {

public abstract void ejecutar(Producto producto);
}



package com.arquitecturajava;

public class TareaEnvioCorreo implements TareaProducto  {

	@Override
	public void ejecutar(Producto producto) {
		System.out.println(producto.getNombre() +"enviado por correo") ;
		
	}

}


package com.arquitecturajava;

public class TareaImprimirProducto  implements TareaProducto{

	@Override
	public void ejecutar(Producto producto) {
		System.out.println(producto.getNombre());
		System.out.println(producto.getId());
		System.out.println(producto.getPrecio());
		
		
	}

}

package com.arquitecturajava;

public class ValidarProducto implements TareaProducto{

	@Override
	public void ejecutar(Producto producto) {
	if (producto.getPrecio()<100) {
		
		System.out.println("producto valido");
	}else {
		
		System.out.println("producto invalido");
	}
		
	}

}

Una vez hemos construido la jerarquía de clases nos queda definir el GestorTareas que se encarga de ejecutar cada una de las tareas.

java command pattern gestor


package com.arquitecturajava;

public class GestorTareas {

	
	public void ejecutar (TareaProducto tarea,Producto p) {
		
		tarea.ejecutar(p);
	}
}


Este diseño nos permite tener una mayor flexibilidad ya que cada tarea es independiente. El añadir nuevas tareas no afecta al resto de tareas. Por otro lado es muy sencillo generar nuevas clases que por ejemplo agrupen tareas.


package com.arquitecturajava;

import java.util.ArrayList;
import java.util.List;

public class SuperTarea implements TareaProducto {

	private List<TareaProducto> lista= new ArrayList<TareaProducto>();
	
	public void addTarea(TareaProducto tarea) {
		lista.add(tarea);
	}
	@Override
	public void ejecutar(Producto producto) {
	
		lista.forEach((t)->t.ejecutar(producto));;
		
		
	}

}

Ahora podemos construir en el programa principal una super tarea:


package com.arquitecturajava;

public class Principal {

	public static void main(String[] args) {
		
		
		SuperTarea st= new SuperTarea();
		
		st.addTarea(new ValidarProducto());
		st.addTarea(new TareaEnvioCorreo());
		
		GestorTareas gt= new GestorTareas();
		Producto p= new Producto(1,"tablet",100);
		
		gt.ejecutar(st, p);

	}

}

Ejecutamos el programa y veremos el resultado en la consola:

Java Command Pattern es una de las soluciones que más flexibilidad aporta al código:

 

It's only fair to share...Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

About Cecilio Álvarez Caules

Cecilio Álvarez Caules Sun Certified Enterprise Architech (J2EE/JEE).

10 Responses to Command Pattern en Java y la gestion de tareas

  1. Juan Sebastian 20 junio, 2017 at 22:23 #

    Excelente explicacion, como siempre !
    Por favor, mas post con patrones…

    • Cecilio Álvarez Caules 21 junio, 2017 at 13:29 #

      gracias 🙂

  2. Erick Daniel Juàrez Gil 6 junio, 2017 at 19:44 #

    Que tal!

    Pregunta: ¿Puedo en el constructor de las tareas mandar objetos que fuera a requerir antes de ejecutarlas?

    • Cecilio Álvarez Caules 7 junio, 2017 at 8:03 #

      no te lo recomiendo porque eso implicaría que nada mas crear el objeto ya tienes los datos necesarios de ejecución y esto no siempre es así. De hecho el patrón comando se utiliza muchas veces para generar grupos de comandos y posteriormente ejecutarlos pasando los parámetros adecuados.

    • Juan 8 junio, 2017 at 9:53 #

      Claro que puedes, si la clase necesita algún servicio externo para llevar a cabo su ejecución.

      • Cecilio Álvarez Caules 8 junio, 2017 at 11:30 #

        Eso es perfectamente posible

  3. Manu 27 mayo, 2017 at 12:35 #

    Yo tengo una duda, por que defines el metodo ejecutar como abstracto y no implementas nada en la interface?

    • Cecilio Álvarez Caules 27 mayo, 2017 at 22:55 #

      Buenas porque en principio un interface dispone únicamente de métodos abstractos , hasta la llegada de java 8 y porque ademas la implementación la realizan cada una de las clases hijas.

      • Juan 8 junio, 2017 at 9:46 #

        eso es redundante e innecesario.

        • Cecilio Álvarez Caules 8 junio, 2017 at 11:30 #

          Uhhn no se como explicarme , no he querido decir que no se pueda realizar lo que tu comentas. Es evidente que si es posible y habrá casos en los que el comando reciba parametros cuando se construye. Pero yo personalmente prefiero crearle con los mínimos parámetros y pasárselos en el execute

Deja un comentario