El patrón Flyweight (Peso ligero) se basa en la idea de compartir objetos que se repiten, en vez de crear una nueva instancia de cada uno de ellos.
Se construyen objetos ligeros a partir de la información redundante (compartida por varios objetos) y se referencian por los nuevos objetos.
Esto optimiza el uso de memoria ya que elimina la redundancia de objetos con propiedades idénticas.
El problema que resuelve es el uso excesivo y sobrecarga de memoria debido a la creación de un gran número de objetos de una clase, que tienen casi el mismo estado o datos (redundancia).
La solución que propone el Flyweight es:
Se comparte el estado intrínseco común entre muchos objetos, esto significa que se crea un número menor de objetos, y cada objeto almacena solo su estado extrínseco.
Este patrón es recomendable cuando:
Eficiencia en el Uso de la Memoria: Reduce significativamente el uso de memoria cuando hay muchas instancias de objetos.
Rendimiento Mejorado: Puede mejorar el rendimiento en sistemas con restricciones de memoria.
Complejidad Adicional: Introduce una mayor complejidad en el diseño.
Compromiso entre Tiempo y Espacio: Puede aumentar el tiempo de ejecución debido a la necesidad de manejar los estados extrínsecos.
Dificultad en la Implementación: Requiere una cuidadosa planificación y ejecución para ser efectivo.
Debemos desarrollar un juego de ajedrez. Cada pieza de ajedrez (como peones, torres, caballos) tiene características comunes, como color y posición, pero también comportamientos específicos (posición en el tablero).
El desafío principal es gestionar eficientemente la memoria y los recursos del sistema, especialmente cuando representamos un gran número de piezas en el tablero.
Crear un objeto separado para cada pieza en el tablero puede ser muy costoso en términos de recursos, especialmente cuando muchas piezas comparten propiedades similares, como el color.
Vamos a usar el patrón Flyweight para optimizar el uso de memoria y mejorar el rendimiento del juego.
Separamos el estado intrínseco común (tipo y color), que se puede compartir entre muchas piezas, del estado extrínseco (posición en el tablero), que es único para cada pieza.
Definimos la interfaz común para todas las piezas ChessPiece con el método dibujar. Creamos una pieza concreta Pawn, que mantiene su estado intrínseco (color). Creamos la clase ChessPiecePosition para manejar el estado extrínseco (la posición). Mediante el ChessPieceFactory vamos a poder gestionar la creación de instancias.
Codificamos en Java lo que preparamos en el diagrama.
Definimos la Interfaz Flyweight:
interface ChessPiece {
void draw(ChessPiecePosition position);
}
Implementamos un ConcreteFlyweight:
class Pawn implements ChessPiece {
private String color; // Estado intrínseco
public Pawn(String color) {
this.color = color;
}
public void draw(ChessPiecePosition position) {
System.out.println("Dibujando peón " + color + " en posición " + position.getX() + "," + position.getY());
}
}
Creamos la clase UnsharedConcreteFlyweight:
class ChessPiecePosition {
private int x, y;
public ChessPiecePosition(int x, int y) {
this.x = x;
this.y = y;
}
// Getters y setters para x e y
}
Creamos la clase FlyweightFactory:
class ChessPieceFactory {
private static final Map PIECES = new HashMap<>();
public static ChessPiece getChessPiece(String color) {
PIECES.computeIfAbsent(color, c -> new Pawn(c));
return PIECES.get(color);
}
}
Usamos el Flyweight en el cliente:
public class Client {
public static void main(String[] args) {
ChessPiece whitePawn = ChessPieceFactory.getChessPiece("Blanco");
ChessPiecePosition position1 = new ChessPiecePosition(0, 1);
whitePawn.draw(position1);
ChessPiece blackPawn = ChessPieceFactory.getChessPiece("Negro");
ChessPiecePosition position2 = new ChessPiecePosition(0, 6);
blackPawn.draw(position2);
}
}
Los participantes que vimos antes son: Flyweight, ConcreteFlyweight, UnsharedConcreteFlyweight, FlyweightFactory, Client:
El patrón Flyweight en nuestro juego de ajedrez digital permite un uso eficiente de la memoria y mejora el rendimiento al compartir piezas comunes, como peones de un mismo color, entre múltiples posiciones en el tablero, mientras se mantiene el estado específico de cada pieza por separado.
Se puede combinar con Flyweight para implementar estructuras lógicas jerárquicas.
Suele ser mejor implementar los objetos State y Strategy como pesos ligeros.