Java FlyWeight Pattern es uno de los patrones de diseño que más cuesta entender ya que implica construir muchas clases para entender su funcionamiento y sus puntos fuertes. Vamos a intentar realizar un acercamiento a él a través de clases sencillas. Imaginemonos que disponemos de la clase MacBookAir.
package com.arquitecturajavaflighweight; public class MacBookAir { private String id; private int ram; private int disco; private static int contador; public MacBookAir(String id, int ram, int disco) { super(); this.id = id; this.ram = ram; this.disco = disco; contador++; System.out.println(contador); } public String getId() { return id; } public void setId(String id) { this.id = id; } public int getRam() { return ram; } public void setRam(int ram) { this.ram = ram; } public int getDisco() { return disco; } public void setDisco(int disco) { this.disco = disco; } } <br data-mce-bogus="1">
Se trata de una clase normal y corriente a la que hemos añadido una variable estática “contador” que almacena el número de instancias que tenemos en memoria. Si construimos el siguiente programa principal:
package com.arquitecturajavaflighweight; public class Principal { public static void main(String[] args) { MacBookAir m1= new MacBookAir("1",4,128); MacBookAir m2= new MacBookAir("2",4,128); MacBookAir m3= new MacBookAir("3",8,256); MacBookAir m4= new MacBookAir("4",8,256); } }
La consola nos mostrará por pantalla algo com esto:
El código es correcto pero ,¿Que pasaría si tuviéramos que construir 100.000 Macbookairs?.
Java FlyWeight Pattern
La realidad es que solo están permitidas 3 o 4 configuraciones de RAM +DISCO en este tipo de equipos. Tenemos por lo tanto un problema de gestión de memoria ya que estamos almacenando los 8 Gb de RAM y 256 de SSD muchas veces. Una solución más elegante sería :
De esta forma solo se almacenaría el valor de cada tipo de MacBookAir una vez y cada ordenador con su numero de serie referencia al que le corresponde esto es un ejemplo Java FlyWeight Pattern. Para construir esta solución necesitaremos varias piezas. En primer lugar vamos a definir un interface y una nueva implementación de nuestro MacBookAir.
package com.arquitecturajavaflighweight2; public interface MacBookAir { public String getId(); public int getRam(); public int getDisco(); }
package com.arquitecturajavaflighweight2; public class MacBookAirImplFlighWeight implements MacBookAir { private String id; private MacLigero macLigero; public MacBookAirImplFlighWeight(String id, MacLigero macLigero) { super(); this.id = id; } public int getRam() { return macLigero.getRam(); } public int getDisco() { return macLigero.getDisco(); } @Override public String getId() { return id; } }
La clase es diferente en muchos aspectos , el primero y más sencillo de entender es que no lleva métodos set ya que el MacBookAir no se le puede cambiar nada una vez comprado . Es una mejora a nivel de implementación , el segundo es que cada MacBookAir solo lleva un ID el resto de los campos los delega en otra clase que tendremos que construir. Estos campos son los comunes a todos los MacBookAir
Vamos a ver su código:
package com.arquitecturajavaflighweight2; public class MacLigero { private int ram; private int disco; private static int contador; public MacLigero(int ram, int disco) { super(); this.ram = ram; this.disco = disco; contador++; System.out.println("contador ligero: "+ contador); } public int getRam() { return ram; } public void setRam(int ram) { this.ram = ram; } public int getDisco() { return disco; } public void setDisco(int disco) { this.disco = disco; } }
Como podemos ver la clase es realmente sencilla. La parte compleja de entender viene compuesta por dos elementos más . El primero es el contenedor de MacLigeros que almacenará los diferentes tipos.
Su código es:
package com.arquitecturajavaflighweight2; import java.util.HashMap; import java.util.Map; public class ContenedorMacLigero { private static Map<String,MacLigero> macLigeros= new HashMap<String, MacLigero>(); public static MacLigero getMacLigero(int ram,int disco) { String clave=ram+":"+disco; System.out.println(clave); if (!macLigeros.containsKey(clave)) { macLigeros.put(clave,new MacLigero(ram,disco)); } return macLigeros.get(clave); } }
Se trata de un HashMap que almacena los diferentes tipos de MacLigeros no podrá haber más de 4-8 combinaciones. El último paso es crear la factoría que construye los Macs.
La factoría nos ayudará a crear de forma correcta los MacBookAirs apoyandose en los MacLigeros.
package com.arquitecturajavaflighweight2; public class FactoriaMacs { public static MacBookAir crearMacBookAir(String id, int ram ,int disco) { MacLigero macLigero=ContenedorMacLigero.getMacLigero(ram, disco); MacBookAir macBookAir= new MacBookAirImplFlighWeight(id,macLigero); return macBookAir; } }
El programa principal cambiará para adaptarse a la factoría:
package com.arquitecturajavaflighweight2; public class Principal { public static void main(String[] args) { MacBookAir m1= FactoriaMacs.crearMacBookAir("1",4,128); MacBookAir m2= FactoriaMacs.crearMacBookAir("2",4,128); MacBookAir m3= FactoriaMacs.crearMacBookAir("3",8,256); MacBookAir m4= FactoriaMacs.crearMacBookAir("4",8,256); } }
Sin embargo los cambios importantes vendrán cuando ejecutemos el programa:
Solo se han creado dos MacBooksLigeros aunque tengamos cuatro MacBooksAir hemos aplicado Java FlyWeight Pattern a nuestro código.
Otros artículos relacionados: Java Proxy Pattern , Java Singleton Class Loaders
[…] Otros artículos relacionados : Patrón Factory , Patrón Flyweight […]
[…] reducir este problema Java de forma interna implementa el patrón flyweight y genera un pool de Strings que se comparte . De esta forma cada vez que nosotros necesitamos crear […]
[…] Otros artículos relacionados: Java StringBuilder , Java WorkFlows , Java Flyweight […]
Entiendo, y al mismo tiempo no :/, Se quieren reducir el numero de instancias que sean idénticas “MacBookAir” para ahorrar memoria, pero se siguen creando 4 de tipo “MacBookAirImplFlighWeight”, la diferencia es que solo cuenta con el ID, pero aun así si se crean 10 “MacBookAir” a través de la factoría se crearían 10 objetos de tipo MacBookAirImplFlighWeight.
-Entonces si es lo que creo, el ahorro de la memoria esta reducir la memoria que ocuparían estas dos variables RAM y DISCO??
En este caso si 🙂
Muchas gracias por el aporte se agradece tener mas ejemplos de este patron 🙂
de nada 🙂
[…] claridad en cuanto al diseño se refiere. Otros artículos relacionados : Java Singleton Pattern , Java FlyWeight CQR Martin […]
Wooww!!, algun libro para aprender un poco mas de este patron ?, en estos tiempos estamos acostumbrados a derrochar memoria y creo que con esto se puede optimizar mucho xD
en el clásico de design patterns 🙂