1. Información general
En este artículo, veremos el patrón de diseño de peso mosca. Este patrón se utiliza para reducir la huella de memoria. También puede mejorar el rendimiento en aplicaciones donde la creación de instancias de objetos es costosa.
En pocas palabras, el patrón de peso mosca se basa en una fábrica que recicla objetos creados almacenándolos después de la creación. Cada vez que se solicita un objeto, la fábrica busca el objeto para comprobar si ya ha sido creado. Si es así, se devuelve el objeto existente; de lo contrario, se crea uno nuevo, se almacena y luego se devuelve.
El estado del objeto flyweight está formado por un componente invariante compartido con otros objetos similares ( intrínseco ) y un componente variante que puede ser manipulado por el código del cliente ( extrínseco ).
Es muy importante que los objetos de peso mosca sean inmutables: cualquier operación en el estado debe ser realizada por la fábrica.
2. Implementación
Los principales elementos del patrón son:
- una interfaz que define las operaciones que el código del cliente puede realizar en el objeto flyweight
- una o más implementaciones concretas de nuestra interfaz
- una fábrica para manejar la creación de instancias y el almacenamiento en caché de objetos
Veamos cómo implementar cada componente.
2.1. Interfaz del vehículo
Para empezar, crearemos una interfaz de vehículo . Dado que esta interfaz será el tipo de retorno del método de fábrica, debemos asegurarnos de exponer todos los métodos relevantes:
public void start(); public void stop(); public Color getColor();
2.2. Vehículo de hormigón
A continuación, hagamos una clase de automóvil como un vehículo concreto . Nuestro automóvil implementará todos los métodos de la interfaz del vehículo. En cuanto a su estado, tendrá un motor y un campo de color:
private Engine engine; private Color color;
2.3. Fábrica de vehículos
Por último, pero no menos importante, crearemos VehicleFactory . Construir un vehículo nuevo es una operación muy costosa, por lo que la fábrica solo creará un vehículo por color.
Para hacer eso, hacemos un seguimiento de los vehículos creados usando un mapa como un simple caché:
private static Map vehiclesCache = new HashMap(); public static Vehicle createVehicle(Color color) { Vehicle newVehicle = vehiclesCache.computeIfAbsent(color, newColor -> { Engine newEngine = new Engine(); return new Car(newEngine, newColor); }); return newVehicle; }
Observe cómo el código del cliente solo puede afectar el estado extrínseco del objeto (el color de nuestro vehículo) pasándolo como argumento al método createVehicle .
3. Casos de uso
3.1. Compresión de datos
El objetivo del patrón de peso mosca es reducir el uso de memoria al compartir la mayor cantidad de datos posible, por lo que es una buena base para los algoritmos de compresión sin pérdidas. En este caso, cada objeto de peso mosca actúa como un puntero y su estado extrínseco es la información dependiente del contexto.
Un ejemplo clásico de este uso es un procesador de texto. Aquí, cada personaje es un objeto de peso mosca que comparte los datos necesarios para la representación. Como resultado, solo la posición del carácter dentro del documento ocupa memoria adicional.
3.2. Almacenamiento en caché de datos
Muchas aplicaciones modernas utilizan cachés para mejorar el tiempo de respuesta. El patrón de peso mosca es similar al concepto central de un caché y puede adaptarse bien a este propósito.
Por supuesto, existen algunas diferencias clave en la complejidad y la implementación entre este patrón y un caché típico de uso general.
4. Conclusión
En resumen, este rápido tutorial se centró en el patrón de diseño de peso mosca en Java. También revisamos algunos de los escenarios más comunes que involucran el patrón.
Todo el código de los ejemplos está disponible en el proyecto GitHub.