Patrón State – Videotutorial

En esta entrega vamos a abordar en profundidad uno de los patrones GoF más utilizados, el patrón Estado o State. Pero antes de entrar a analizar los detalles del patrón debemos preguntarnos que se entiende en si por estado. Un sinónimo bastante próximo a lo que se entiende por estado es memoria. Y en lo que se refiere a memoria, en el caso de un programa, este es el terreno de las variables en general: campos, variables, argumentos de entrada, etc. De ahí que podamos decir que el estado de un programa en un momento dado sea el valor de todas y cada una de la variables del programa; del mismo modo, el estado de un objeto sería el valor que toman en un momento dado todas sus «variables», es decir, sus campos de instancia.

Sabemos que en un lenguaje como java, diseñado para favorecer la programación mediante el paradigma de la orientación a objetos, la clase es la entidad de nivel superior que encapsula al resto de miembros.
Estos miembros pueden representar datos (información), los llamados campos, o pueden representar comportamiento, los llamados métodos (encapsulando una serie de instrucciones).

Conocemos tambien que en lo que respecta a campos de una clase, cuyo papel como hemos dicho es almacenar información en memoria, algunos pueden ser compartidos por todas las instancias de la clase o estaticos, mientras para otros cada instancia tiene su propia versión o copia del campo, los campos de instancia.

Dicho todo esto, si en una clase, nada más se define comportamiento, es decir, sus miembros son únicamente métodos, entonces, este objeto carece de estado. Y esto tiene una implicación práctica muy importante. Por un lado, no importa cuantas veces se llame a un mismo método de ese objeto, si los argumentos de llamada son los mismos el resultado o comportamiento será siempre el mismo. Por otro lado, dará igual también el orden en el que se llame a los métodos de ese objeto porque su comportamiento no depende de si se ha llamado a otro método previamente. Como no hay campos de instancia, el objeto carece de estado, y sin estado «no hay memoria sobre el pasado».

Por tanto, cuando hablamos de estado, nos estamos refiriendo al valor que contienen en un momento dado los campos de una clase. Si el ámbito de estos campos ha sido declarado privado (como preconizan las buenas prácticas de la POO), entonces la única forma de modificar el valor de alguno de estos campos del objeto es mediante la llamada a alguno de sus métodos, siendo el caso más característico de todos ellos un método «setter».

En este punto, llegamos al caso de que algún método de la clase quiera asegurarse de que se ha llamado previamente a algún otro método, cosa que podrá averiguar indirectamente comprobando el valor de algún campo del objeto, o dicho de otra forma, comprobando el estado del objeto.

La necesidad de comprobar el estado del objeto es un hecho bastante común en programación, puesto que muchas veces para poder llevar a cabo su labor el método invocado necesita estar seguro de que se cumplen unas determinadas precondiciones, ya que de no ser asi, puede no tener sentido realizar su trabajo. Y aqui está «la madre del cordero». La comprobación de que se cumplen estas precondiciones, a partir de analizar el valor de los campos que sea necesario comprobar, puede requirir el uso de estructuras condicionales, cuyo nivel de anidamiento y ramificaciones hagan muy complicado seguir la pista de la lógica de esas instrucciones. Estas bifurcaciones, si bien pueden compilar sin errores de sintaxis pueden no estar haciendo lo correcto desde un punto de vista semántico, en cada combinación de valores posible que puedan tomar los campos del objeto, el estado.
Ademas de esto, es posible que una de estas precondiciones pueda ser necesario comprobarla en mas de un método, lo cual conlleva copiar y pegar la expresión condicional y/o ramificaciones idénticas en más de un sitio del código. Bienvenidos a la pesadilla del mantenimiento del código!!!!

Existen técnicas alternativas más eficientes, en base a constatar que básicamente lo que estamos haciendo es seguir la pista a algunas de las combinaciones de valores que pueden tomar algunos de los campos del objeto. Cuando se da alguna combinación de estas decimos que el objeto se encuentra en el estado X, si se da otra de estas combinaciones diremos que su estado es Y, etc.

Llegados a este punto es posible que tengamos un número finito de estados. En este caso, estamos ante lo que se conoce como una máquina de estados finita o FSM. Nuestra objeto, por tanto, no es más que una máquina de estados finita, y la podremos programar siguiendo algunas de las técnicas para implementar una FSM. Entre todas las diferentes técnicas que existen, la que mejor saca partido de la POO es precisamente la que consiste en aplicar el patrón State. Por ello, podemos decir que el patrón State no es más que la implementación de una FSM mediante el uso de la POO.

Aqui teneis el videotutorial sobre el patrón de diseño State.

Patrón Observer (II) – Métodos Pull y Push para el intercambio de información entre sujeto y observador

Seguimos con el ejemplo donde aplicabamos el patrón de diseño Observer a un código que realizaba la autenticación de usuarios. En este ejemplo vimos que la manera de desacoplar los componentes era mediante el uso de este patrón.

En el ejemplo, los componentes observadores reciben la información necesaria para realizar su labor cuando reciben la notificación junto con esta en forma de parámetros de entrada del método update. Cuando junto con la notificación, los observadores reciben la información de estado del sujeto, aquella que necesitan para llevar a cabo su tarea, a esta forma de comunicación de la información se la denomina «Push», dado que el sujeto «empuja» la información de su estado junto con la propia notificación.

El mayor inconveniente que puede tener el método push, tal y como lo hemos implementado, para hacer llegar la información de estado desde el sujeto a los observadores que la requieran es que no es flexible ante el cambio. Si las especificaciones futuras hicieran cambiar la información de estado, por ejemplo, ampliandola para informar adicionalmente sobre el password introducido, número de intentos de autenticación realizados, etc. ello implicaria modificar la firma del método update() en la interfaz Observer, lo que provocaría la rotura del código de todos los componentes observadores actualmente implementados, puesto que la firma de la implementación de sus métodos update() ya no coincidiría con la firma tal como quedara redefinida en la interfaz.

Método Pull

Ante esto, existe la posibilidad de no comunicar la información de estado del sujeto junto con la notificación, sino que la notificación simplemente sirva para indicar al observador que ahora es el momento de pedirle la información de estado al sujeto porque acaba de realizar la acción. Es entonces el observador, quien mediante una referencia al sujeto, invocará los métodos necesarios para recuperar la información de estado del sujeto. El observador «estira» de la información por eso el método se denomina Pull.

En el método Pull el sujeto debe de proporcionar una interfaz (una serie de métodos) para que los observadores puedan obtener la información de estado que necesitan. En el ejemplo, esto mismo es llevado a cabo mediante la creación de dos «getters» getUser() y isSuccess() de ambito público. El observador, mediante un referencia al sujeto, puede invocar estos métodos y «estirar» de la información.

El observador necesita contar con una referencia al sujeto al cual está observando que pueda untilizar dentro de su implementación del método update(). Existen varias aproximaciones para que el observador cuente con esa referencia. Podemos bien pasársela en el constructor, o bien crear un setter para establecerla, o como última posiblidad que se reciba como un parámetro del propio método update() así: void update(Subject source). Hacerlo en el constructor es muy rígido porque implica que el obervador no puede cambiar de sujeto durante toda su vida. Hacerlo mediante un setter si permite cambiar de sujeto, pero como ya veremos más adelante, implica que vamos a observar un solo sujeto a la vez. Por último, si decidimos que la referencia al sujeto nos llegue como parámetro de entrada en el método update, podremos registrar el componente para que observe varios sujetos al mismo tiempo ya que gracias a este parámetro se podrá identificar que instacia de sujeto concretamente está notificando. En el ejemplo solo existe un objeto sujeto, la instancia de AuthenticationManager, por tanto tiene sentido definir un setter.
Este setter (implementado de una forma perfecta y realista) deberia comprobar si el componente ya está actualmente observando otro sujeto y desregistrarse de su lista de observadores y a continuación registrarse para observar el nuevo sujeto.

public void setSubject(Subject subject) {
	if(this.subject != null) this.subject.unregister(this);
	this.subject = subject;
	subject.register(this);
}

Dentro del método update el inconveniente que se nos presenta es que no podemos obtener la información de estado del sujeto a no ser que convirtamos con éxito la referencia de tipo Subject más abstracta a una más concreta del tipo concreto del sujeto AuthenticationManager.
Para asegurarnos de que el downcasting tiene exito podemos comprobar si la referencia almacenada dentro el campo subject es de tipo AutheticationManager haciendo uso del operador instanceof de java.

if (subject instanceof AuthenticationManager) {
	AuthenticationManager authMng = (AuthenticationManager) subject;
        
        //Aqui código que recupera informacion de estado del sujeto concreto
}

Este es el mayor inconveniente que presenta el método pull, a parte de obligar al observador a solicitar la información de estado que necesita, este debe conocer el tipo concreto del sujeto o tratar de averiguarlo, con lo cual estará acoplado con una implementación concreta, rompiendo el principio de diseño de programar para una interfaz y no para una implementación.

Método Push

Por otra parte tenemos en método push, que ya hemos comentado basa su estrategia en propagar la información de estado junto con la notificación. El problema como hemos apuntado es que la información de estado en si puede ser motivo de cambio en futuras ampliaciones, lo que conlleva cambios en la firma del método update. No obstante podemos solventar este problema si encapsulamos toda la información de estado que vamos a propagar en una instancia de un objeto diseñado precisamente para encapsular toda esta información de estado. Con esto, la firma del método update solamente necesita contar con un parámetro de este tipo. En el ejemplo este papel lo desempeña la interfaz NotificationInfo.

public interface NotificationInfo {	
	String getUser();	
	boolean isSuccess(); 
}

Normalmente y en previsión de que un observador puede observar más de una instancia de tipo sujeto al mismo tiempo, se establece otro parámetro en la firma del método update de la interfaz Observer para, en caso de estar observando varios sujetos, poder identificar de que sujeto se trata, en el caso de que debamos interaccionar con él. Quedando, por tanto, la interfaz Observer de la siguiente manera:

public interface Observer {	
	void update(Subject source, NotificationInfo state);
}

El código que implementa el método update en una clase observador puede acceder a la información de estado, en el ejemplo el usuario y el resultado de la validación mediante el parámetro state.

En definitiva, si en lugar de colocar cada pieza de información asociada como un parámetro independiente en la lista de parámetros del método update los encapsulamos en un nuevo tipo de objeto que cuente con una interfaz para acceder a todos ellos, no será necesario modificar nada en el código que ya tuvieramos desarrollado si posteriormente hubiera que añadir más información de estado, como sucedia con el método pull. Pero, al contrario que en el método pull, el observador no está obligado a conocer y trabajar con referencias del tipo concreto de sujeto. Por este motivo, casi todos los sistemas utilizan esta aproximación basada en push más un objeto que encapsula la información de estado.

Aqui teneis el video donde podeis ver el desarrollo de ambos ejemplos.

Patrón Observer – Ejemplo de aplicación del patrón en Java

El patrón de diseño Observer se caracteriza principalmente por la reducción en el acoplamiento entre distintos componentes de una aplicación. Si nos encontramos en una situación en la que uno de estos componentes se acopla con el resto de ellos, como en el ejemplo de código que vamos a ver, siguiendo el patrón de diseño Observer daremos a este componente el rol de sujeto, el resto serán observadores.

La ventaja que proporciona el uso del patrón observador es que el código de la clase que hace de sujeto, que es la que tiene la información de cuando y por qué se deben hacer ciertas «tareas», quedará liberada de llamar directamente a los componentes que realizan estas «tareas». Dado que, llamarlos directamente implica conocer el tipo concreto de estos componentes y su interfaz concreta, se produce el acoplamiento con estos.

En lugar de esto, la clase sujeto notificará a los componentes cuando lo estime conveniente porque se da el motivo para ello. El patrón Obervador facilita que la notificación se produzca a través de una interfaz bien definida y común a todos estos componentes que se va a notificar. Esta interfaz común viene dada mediante la interfaz Observer que cuenta con un método que se suele denominar update().

Es tarea del sujeto mantener una lista de objetos interesados en ser notificados, con una serie métodos (register y unregister) para que los componentes observadores se registeren y se den de baja en esta lista. El sujeto pues, ya no necesita conocer el tipo concreto de los componentes, el tipo de las referencias con las que trabaja para notificar a los componentes es del tipo abstracto Observer. Tampoco depende de cuantos componentes estén registrados y si reciben la notificación ni de como la procesan.

En conclusión, todo esto permite que al programa al que aplicamos el patrón observador, podamos añadir nuevos componentes adicionales que amplien la funcionalidad con nuevas tareas en futuras modificaciones del código sin que sea necesario hacer cambios en el código de la clase notificadora o sujeto. Bastará simplemente con instanciar un objeto de este nuevo componente y registrarlo para que observe al sujeto.

En el ejemplo, tenemos una clase para autenticar usuarios, su responsabilidad es comprobar unas credenciales (usuario y contraseña) y validarlas, concluyendo si son correctas o no. Por otro lado, existen tareas adicionales, dependientes de si la validación ha tenido exito o no, son variadas y abarcan desde la carga de archivos del perfil, el registro de auditoria, la monitorización de ataques, etc.

Si todo esto lo hacemos en el código de la clase de autenticación estamos rompiendo el principio de responsabilidad única, y lo peor, estamos creando una dependencia en esta clase por cada uno de estos componentes que maneja directamente. Ampliaciones en este sistema para que trabaje con un nuevo compomente implica cambios en el código de la clase de autenticación. Los cambios en los componentes existentes tambien pueden afectar al código de la clase de autenticación.

Daremos a la clase que autentica el rol de sujeto, porque es la que tiene conocimiento de CUANDO suceden la acción que da lugar a que sea necesario escribir una entrada en el registro de eventos, cargar perfiles, activar la monitización de ataques, etc. y el rol de observadores al resto de componentes porque son los que tienen el conocimiento de COMO registrar, cargar, monitorizar, etc. Estos se registran en la lista de observadores del sujeto y este les noficará cuando deben realizar su labor, además de la información adicional necesaria.

Aqui os dejo el video tutorial.

El asunto de la comunicación adicional que el observador necesita para realizar su trabajo no es una cuestión menor y existen varias posibilidades. Estas variantes del patrón Obsever en función de como se facilita la información adicional a los observadores se denominan Push y Pull. En el próximo post analizaremos cada una de ellas para ver sus ventajas e inconvenientes.

Creando el módelo y un controlador para la entrada mediante el ratón

Continuamos el videotutorial sobre el desarrollo de videojuegos. En esta segunda entrega se llevan a cabo principalmente 2 tareas. La primera consiste en eliminar todo el código contenido dentro de la clase Gameloop relacionado con el almacenamiento y la actualización de la información necesaria para dibujar la pelota en la posición correspondiente en cada frame. La segunda tarea añadirá nueva funcionalidad al programa demostración aportando la posibilidad de que el usuario interaccione con la pelota mediante el uso del ratón.

Como primera tarea hemos dicho que vamos a eliminar de la clase Gameloop la responsabilidad de manejar la información necesaria para dibujar la pelota y actualizar su posición. Toda esta responsabilidad recaerá en una nueva clase, GameObject, que formará parte del conjunto de clases cuya cometido consiste principalmente, como ya se ha apuntado, en modelar las características intrínsecas que definen los elementos de que se compone el juego. Por tanto, le conciernen tareas como la de almacenar toda la información asociada a los componentes del juego y definir los métodos necesarios para definir la lógica interna, manipular y acceder a esta información.
Este grupo de clases forman lo que se denomina MODELO en el patrón de arquitectura de aplicaciones conocido como MVC (Modelo – Vista – Controlador).
En esta arquitectura, las clases que componen el modelo, tiene la resposabilidad que hemos mencionado anteriormente.
En nuestra demo, la clase GameObject, será de momento la única clase definida en el modelo, para que este sea lo más simple posible a efectos de que el código de la demo se mantenga sencillo.

En la segunda parte del video, se añadirá la funcionalidad al programa para que el usuario haga click en un punto de la pantalla del juego y la pelota cambie la dirección y se dirija a este punto en que el usuario hizo click. La pelota describirá un movimiento parabólico desde el punto inicial en el que se encuentra en el momento en que usuario ha efectuado el click hasta ese nuevo punto destino, donde alcanzará su altura máxima y a partir de ahi empezará su descenso.

En la aplicación de ejemplo, la clase en la que recaerá la responsabilidad de controlar la respuesta a la entrada del usuario mediante el ratón será la clase MouseGameController. Esta clase cumple el papel de un controlador según el patrón MVC. Según las directrices del MVC, los controladores son los objetos que se encargan de lidiar con la entrada del usuario. Las acciones que el usuario realiza, click de ratón, pulsaciones de teclas, etc. el controlador las traduce en una llamada a alguno de los métodos del modelo. Por tanto, es misión del controlador interpretar la acción realizada por el usuario y ordenar al modelo realizar una acción en repuesta a la acción del usuario.

El controlador no cuenta directamente con las instrucciones para responder a la acción que usuario demanda, eso es tarea del modelo. Pero si sabe cuando el usuario da la orden porque permanece a la escucha de la entrada del usuario. La clase MouseGameController para realizar su labor debe observar a la vista, en nuestro caso concreto el JFrame, que es quien hace el papel de sujeto. MouseGameController es un observador y el JFrame es el sujeto, he aquí un caso de uso del patrón observador. De momento, vamos a suscribir al objeto observador (la instancia de MouseController) en el método init() del Gameloop. El controlador necesita una referencia al modelo para proceder a invocar el método que este haya considerado necesario despues de interpretar la entrada del usuario, dicha referencia se la proporcionaremos en el constructor.

Para terminar de cerrar la breve descripción del patrón MVC, diremos que la misión de la vista consiste en plasmar de una manera visual la información que mantiene el modelo. Por tanto, la responsabilidad de cualquier clase que forma parte de la vista es «pintar» la información. En el caso del juego, la vista la componen las clases que trabajando con una referencia a objetos del modelo, leen su información y a partir de ella «dibujan» en un espacio de presentación como la ventana de un JFrame. En los siguientes videos, está será la siguiente responsabilidad que habrá que extraer de la clase GameLoop pues todavia se nos ha quedado en ella.

Aqui teneis el video del tutorial

Y aqui el video correspondiente a la explicación sobre las fórmulas aplicadas para obtener la velocidad inicial vertical y horizontal a aplicar a la pelota ante un click de ratón por parte del usuario: La fisica del movimiento parabólico.

El bucle principal de un videojuego

En este video se describe la arquitectura básica de una aplicación consistente en un videojuego. El nucleo de este tipo de aplicaciones consiste en un bucle que repite en cada paso 2 acciones secuencialmente. La primera de ellas es la actualización de los valores que definen las caracteristicas de los elementos del juego (el modelo) teniendo en cuenta el tiempo que ha pasado desde la última actualización. La segunda consiste en la visualización en pantalla de los cambios, esta nueva «realidad», de forma gráfica tras la generación, a partir de la información aportada por los elementos del juego (el modelo) una vez actualizada, de lo que se conoce como un frame.

El proceso se repite una y otra vez, a un ritmo fijo determinado por el denominado framerate, por ello, antes de terminar cada pasada del bucle, este debe comprobar el tiempo que le ha sobrado despues de las tareas de actualización y renderizado del frame para proceder a dormir el hilo de ejecución el tiempo restante. Todo esta responsabilidad se asigna a una clase que se encargará de controlar que la acciones de actualización y renderizado se producen a un ritmo perfectamente sincronizado e independiente de la velocidad de la CPU.

Patrón Estrategia – Videotutorial

El patrón estrategia es uno de los patrones de comportamiento más importantes y utilizados dentro de del grupo de patrones Gof. Tanto es así, que muchos lenguajes ofrecen características integradas en el propio lenguaje para hacer incluso más facil de utilizar este elemento de diseño cuando se implementa en uno de estos lenguajes. Uno de estos lenguajes es java.

Aqui os dejo un videotutorial que trata a nivel teórico el patrón de diseño Estrategia explicando sus beneficios y situaciones en la que deberia aplicarse.

Patrón Estrategia – Una clase para ordenar listas de elementos IV

La última mejora que podemos llevar a cabo va a permitir facilitar el uso del sorter desde el código cliente. Vamos a ver como. Si nuestro sorter ordena listas de objetos, como por ejemplo manzanas, y estos objetos se distinguen por poseer una serie de caracteristicas o propiedades, en el caso de las manzanas color y peso; podemos hacer que el codigo cliente solo tenga que elegir cual es la caracteristica de entre todas las que tiene una clase de ojetos para ordenarlos en base a esta propiedad elegida.

Qué caracteristica vamos a escoger para ordenar sera la estrategia, que llamaremos selector

public interface Selector<TSource, TResult> {
	TResult select(TSource item);
}

Como vemos está parametrizado para dos tipos, el tipo de entrada TSource y el tipo de resultado. En nuestro caso TSource será el tipo del elemento, Manzana y TResult será el tipo de la caracteristica elegida, String si es el color o double si se trata de el peso.

La interfaz define un único método select que recibe un TSource y devuelve un TResult. En el caso de seleccionar el color de las manzanas Apple y String respectivamente.

Veamos 2 declaraciones de estrategias en el método main de la clase principal del programa.

//Declara las dos estrategias de seleccion
Selector<Apple, String> colorSelector = (Apple a) -> a.getColor();
Selector<Apple, Double> weightSelector = a -> a.getWeight();

En el segundo selector, en la expresión lambda no hemos especificado el tipo de la entrada a a la expresión, el compilador la infiere observando que la expresión lambda se asigna a la variable weightSelector, que es de tipo Selector, y como el método select de la interfaz es TResult select(TSource item) y dado que el selector ha sido definido de forma geerica Selector queda claro para el compilador que TSource es Apple.

Veamos ahora como queda la nueva sobrecarga del método sort que acepta un selector.

	public static <TSource, TResult extends Comparable<TResult>> void sort(
			TSource[] items, Selector<TSource, TResult> selector) {

		Comparer<TSource> comparer = 
				(x, y) -> selector.select(x).compareTo(selector.select(y));

		sort(items, comparer);	
	}

Lo primero que observamos, es que usa el selector para definir un comparador mediante una expresión lambda formada a partir de llamadas al selector y luego delega en el método sort anterior que utilizaba estrategias de comparación para su funcionamiento parsandole como argumento ese comparador construido internamente.

La firma del método es un poco complicada por el hecho de que se está aplicando una restricción al parámetro de clase TResult: TResult extends Comparable. Como TResult no sirve cualquier tipo de clase, si no solamente aquellas que sean de tipo Comparable o sus subclases. Esto garantiza que dado que TResult implementa Comparable entonces se podrá llamar al método compareTo, que es justo lo que hace la expresión lambda con el valor devuelto por el selector.

La expresion lambda selecciona mediante el selector la misma característica en ambos objetos x e y, y puesto que queda garantizado que la característica es de tipo Comparable o una subclase se puede usar el método compareTo con ellas.

Entonces, ¿óomo será el código para ordenar por color o por peso?

Sorter.sort(apples, weightSelector); 
printApples();
	
Sorter.sort(apples, colorSelector); 
printApples();

Incluso podemos ser más directos y no crear variables intermedias escribiendo la expresión lambda directamente en la llamada. Es como si un comportamiento también fuese considerado un dato de entrada en la llamada.

Sorter.sort(apples, a -> a.getColor());
printApples();

En este caso, como la caracteristica la devuelve un método, el getter, podemos utilizar la nueva característica de java consistente la capacidad para asignar a variables de interfaz referencias directas a nombres de métodos.

Sorter.sort(apples, Apple::getWeight);
printApples();

El método getWeight() es un método de instancia, lo que quiere decir que en realidad recibe un argumento más en su llamada además de los que explicitamente se definen en su firma. Ese argumento adicional es la instancia que lo invoca, es decir, la llamada será x.getWeight() o y.getWeight(), etc y esa x o esa y que son referencias a objetos Apple son «argumentos» de entrada en la llamada. Esto es lo que hace que x.getWeight() devuelva el peso de la manzana x y y.getWeight() el peso de la manzana y, x e y «parametrizan» el resultado de la llamada.

Es por eso que la expresión Apple::getWeight es válida para asignar a una interfaz Selector cuyo método es TResult select(TSource source) El método select necesita un argumento, aunque getWeight() no recibe ninguno, pero eso es de forma explicita porque al ser un método de instancia si que recibe la refencia al objeto que lo invoca x si hicieramos x.getWeight(). Por tanto, a efectos prácticos es como si se sustituyera por una versión estática getWeight(Apple a) que ya es compatible con el método select de la interfaz.

Patrón Estrategia – Una clase para ordenar listas de elementos III

Seguimos con el ejemplo del sorter de posts anteriores. Vamos a ver algunas mejoras en la usabilidad. En primer lugar la forma ordenar mediante una nueva estrategia consiste en cambiar de estrategia llamaando al método setComparer() proporcionando la referencia al objeto comparador y despues llamar al metodo sort una vez que el sorter cuenta con su nuevo comparador.

Podemos hacer que esto esto suceda en un solo paso si sobrecargamos el método sort para reciba ademas de la lista de elementos a ordenar, un segundo argumento que será directamente la estrategia a aplicar. En este caso, el método puede ser estatico porque no necesita acceder a ningún campo de instancia de la clase. ¡No es necesario instanciar un Sorter para usar la ordenación!

public static <T> void sort(T[] items, Comparer<T> comparer) {

		for (int i = 0; i < items.length; i++) {
			// Asumir de partida que el valor menor de la parte aun no ordenada
			// del array esta en la primera posicion de la parte aun no ordenada
			int notOrderedLowerValueIndex = i;
			// Recorrer el resto del vector para encontrar otro menor
			for (int j = i + 1; j < items.length; j++)
				// Si se encuentra un valor menor en la posicion j
				if (comparer
						.compare(items[j], items[notOrderedLowerValueIndex]) < 0)
					notOrderedLowerValueIndex = j; // nueva posicion del menor j

			// Si el valor de la posicion i no estaba en su sitio
			// porque hemos encontrado en una posicion distinta otro valor aun
			// menor intercambiar las posiciones
			if (i != notOrderedLowerValueIndex) {
				T aux = items[i];
				items[i] = items[notOrderedLowerValueIndex];
				items[notOrderedLowerValueIndex] = aux;
			}
		}
	}

Ver como se realizar la llamada, se hace uso directamente de la clase Sorter, no es necesario instanciar un objeto Sorter.

//Usa la version estática del método sort con la estrategia como argumento de entrada
Sorter.sort(apples, byWeight);
printApples();

Patrón Estrategia – Una clase para ordenar listas de elementos II

En el post anterior hemos visto como definir una clase para ordenar colecciones de elementos de cualquier tipo y criterio de ordenación, elegido desde fuera de la clase Sorter por el codigo cliente, gracias al patrón estrategia.

Hemos visto que para definir una nueva estrategia es suficiente con crear una clase que implemente la interfaz de la estrategia, como en el caso de la clase ByWeightAppleComparer.

Ahora vamos a ver otras formas para proporcionar la estrategia con la que una instancia Sorter va a comparar los elementos de la colección sin que sea necesario crear una nueva clase.

Forma 1: Mediante clases anonimas

Creamos un nuevo objeto uilizando directamente el tipo de la interfaz. Lo podemos guardar en una variable del tipo de la interfaz y luego pasarselo como argumento al constructor de la clase Sorter cuando construimos un objeto Sorter.

Comparer<Apple> comparer = new Comparer<Apple>() {

	@Override
	public int compare(Apple x, Apple y) {

		return Double.compare(x.getWeight(), x.getWeight());
	}
};		

Sorter<Apple> appleSorter = new Sorter<Apple>(comparer);
appleSorter.sort(apples);
printApples();

Tambien podiamos haber cambiado la estrategia de un objeto Sorter existente. Recordemos que gracias, al patrón estrategia, el comportamiento del objeto sorter es dinámico, puede cambiarse en tiempo de ejecución. Veamos, ahora como hacer que ordene por color.

appleSorter.setComparer(new Comparer<Apple>(){

			@Override
			public int compare(Apple x, Apple y) {

				return x.getColor().compareToIgnoreCase(y.getColor());
			}});

appleSorter.sort(apples);
printApples();

Para cambiar la estrategia de un objeto Sorter simplemente se llama al método setComparer proporcionando la referencia a la nueva estrategia. En este caso la proporcionamos directamente conforme se crea, sin almacenarla en una variable puesto que no vamos a necesitar la referencia nuevamente en el código cliente.

Forma 2: Mediante expresiones lambda

El segundo caso, es un caso típico, pero a la vista del código podemos apreciar que sólo la linea 6 aporta algo de información util, esto es, la forma de comparar por color, todo lo de alrededor es puro envoltorio, lo cual complica ver la parte esencial, el código de comparación de la linea 6 que queda enterrado entre tanta paja sintáctica. Las clases anonimas tienen este problema, que se soluciona con una característica nueva que incorpora Java 8: las expresiones lambda. Para más detalle sobre las expresiones lambda podeis mirar mi otro post Expresiones lambda.

La interfaz de la estretagia Comparer define único método, lo que la convierte en candidata a ser usada junto con expresiones lambda. Podemos asignar una expresión lambda a una variable del tipo de la interfaz.

public interface Comparer<T> {

	int compare(T x, T y);
}

La expresión lambda, para ser compatible, debe contar en su izquierda con dos identificadores y en la parte derecha debe haber una expresión que de como resultado un int.

//Un comparador por peso mediante expresion lambda
Comparer<Apple> byWeight = (x, y) -> Double.compare(x.getWeight(), y.getWeight());

Podemos ver que la sintaxis es ahora mucho más concisa.

sorter.setComparer(byWeight);
sorter.sort(apples);
printApples();

Incluso podemos escribir directamente la expresión lambda como argumento de entrada en la llamada al constructor de un Sorter.

//Crear un sorter proporcionando su estrategia de comparación
Sorter<Apple> sorter = new Sorter<Apple>(
				(x, y) -> x.getColor().compareToIgnoreCase(y.getColor())
				);

sorter.sort(apples);
printApples();

Por tanto, no es necesario crear ninguna clase ni objeto anónimo, directamente se proporciona al objeto sorter la expresión con la estrategia para comparar. Siendo el código mucho más claro, limpio y directo.

Expresiones lambda en java 1.8

Una expresión lambda equivale a escribir una especie de función matemática del tipo

f(x) = x * 2 + 3

En este caso leemos que dado un x, el resultado será el de multiplicar por 2 el valor de x y sumarle 3.

Para expresar esto mismo con una expresión lambda hariamos:
(x) -> x * 2 + 3

Expresar esto en programación requiría escribir un método o función, que a su vez debe encapsulsarse en una clase.

public class Contenedora implements Funcion {

	int funcion(int x) {
		return 2 * x + 3;
	}
}

Si la clase contenedora implementa una interfaz Funcion definida de esta manera

public interface Funcion {

	int funcion(int x); 
}

Entonces podemos asignar una referencia a un objeto de tipo Contenedora a una variable de tipo Funcion
y utilizar la variable para invocar al objeto que realiza la operación.

Funcion f1 = new Contenedora();
f1.funcion(25);     // 25 * 2 + 3

Todo este envoltorio en clases es necesario debido a que anteriormente java no permitia asignar funciones a variables, solamente se podían asignar valores de tipos de datos primitivos y referencias a objetos. Las funciones eran elementos de segunda categoría y se tenían que encapsular en clases contenedoras.

A partir de Java 8 si una interfaz como la que hemos definido, Funcion, contiene un único método, se podrá asignar directamente a una variable del tipo de la interfaz una función cuya firma sea compatible con la firma de este método.

class Funciones {
static int dobleMas3(int x) {
		return 2 * x + 3;
	}

//mas funciones dentro de la clase
}

Podemos usar la funciín de arriba dobleMas3 de este modo:

Funcion f1 = Funciones::dobleMas3;
f1.funcion(25);     // 25 * 2 + 3

A la variable f1, de tipo Funcion (una interfaz de un único método) le asignamos directamente el nombre de una función.

Pero existe un detalle que todavía se puede mejorar: las clases anónimas permiten asignar a una variable del tipo de la interfaz una referencia a un objeto nuevo anónimo creado así porque no existe una clase entre las que implementan la interfaz que reuna las características que buscamos y solamente vamos a crear una instancia objeto sola esa vez. ¿Para qué crear una clase implementadora de la interfaz a propósito para luego sólamente utilizar una instancia de esa clase? Es el caso de los «listeners» de Swing

Bien, pues esta misma situación también se puede presentar cuando estamos considerando funciones. ¿Y si no existe en el código una función que realice las instrucciones que yo quiero llevar a cabo?¿La defino en alguna parte, le doy un nombre y luego la asigno como hemos visto en el ejemplo de la función dobleMas3?

La respuesta es que no es necesario, igual que existen los objetos anónimos existen las funciones anónimas, y estas son las denominadas expresiones lambda.

Por tanto, supongamos que queremos asignar a esa variable f1 una función que no existe, en este caso haríamos algo así:

Funcion f1 = (x) -> x * 2 + 3; //expresion lambda
f1.funcion(25);     // 25 * 2 + 3

Una vez visto el ejemplo, vayamos a la sintaxis. Una expresión lambda se compone de 2 partes: parte izquierda y parte derecha, separadas por los caracteres ->. En la izquierda es donde se indican las variables de la expresión y en la derecha está el calculo que se realiza con esos valores de entrada proporcionados.

Se han de cumplir una serie de requisitos para que una expresión lambda se puede asignar a una variable (o pasarse como argumento en una llamada)

  1. La expresión lambda debe definir en su parte izquierda tantos identificadores como el número de parámetros que tiene la función única definida en la interfaz de cuyo tipo es la variable o parámetro de la llamada al que queremos asignarle la expresión.
  2. La expresión que realiza el cálculo en la parte derecha, cuando se evalue, debe proporcionar un resultado cuyo tipo debe coincidir con el tipo de valor de retorno que define la función en la interfaz

Como consecuencia de todo esto, podemos concluir que a partir de este momento, comportamiento o funcionalidad acaban convirtiéndose en información almacenable en variables y es posible pasarlo a otras funciones que la esperan como argumento de llamada. De modo que, igual que el resultado de una función depende de los valores con los que es invocada, el comportamiento de la función puede cambiar si al llamar a la función pasamos como argumento distintos comportamientos (funcionalidad o código). La implementación de un método de una clase puede parametrizar no sólo información para llevar a cabo su tarea sino que además puede parametrizar comportamientos (fragmentos de código) en los cuales delegar. En otras palabras, una parte del código pueda porporcionar no solo datos sino también instrucciones o código a otra parte cuando esta última es invocada.