WeakHashMap y una posible solución de diseño

WeakHashMapHace poco descubrí la clase WeakHashMap de java y encontré un ejemplo de su uso con una idea interesante que no se me había ocurrido y que puede ser una alternativa buena de diseño para resolver determinados problemas. Me "explayo":

Imagina que en tu empresa haces proyectos de software en los que siempre hay listados de personas, pero la información que se guarda de cada persona varía de un proyecto a otro. Por ejemplo, en todos los proyectos las personas tienen DNI, nombre, apellidos, fecha de nacimiento, sexo, etc. Pero en un proyecto que hacéis de un taller de coches la persona tiene además asociado el coche que tiene, con su marca, modelo, etc. En otro proyecto que hacéis de nóminas la persona tiene también su cargo en la empresa, sueldo base, complementos, antigüedad, etc. Y así con cualquier tipo de proyecto que se os ocurra relacionado con personas.

Como somos una empresa espabilada y vemos que siempre tenemos personas en los proyectos y unos datos que siempre son comunes, decidimos hacernos una librería en la que tenemos la clase Persona con los atributos comunes, paneles para editar personas, JTable de personas, daos de persistencia en bd, tablas en bd, etc.

Cuando llega un proyecto concreto debemos ampliar los datos de esa Persona que tenemos en la librería. Y se nos presentan varias opciones.

La que rápidamente piensa cualquiera que haya estudiado orientación a objetos (y quizás sin mucha experiencia), es heredar de Persona y añadir en la clase hija los atributos adicionales. Así, en el ejemplo de nuestro taller, tendríamos PersonaConCoche extends Persona y le añadimos todo lo relativo al coche. Esta solución se puede hacer y funciona, pero al implementarla vemos que no acaba de convencer. El código que hagamos adicional para el taller va a tratar con una Persona a la que hay que hacer cast a PersonaConCoche, debemos rellenar los datos de un mismo objeto en dos consultas de bd e insertarlo en dos veces, unos campos primero y otros después, posiblemente en el orden adecuado, etc, etc.

La siguiente opción que se nos ocurre es poner un método en nuestra clase Persona que sea setDatosAdicionales(datosAdicionales). ¿Pero qué tipo ponemos a esos datosAdicionales en nuestra librería general para que nos sirva en cualquier proyecto?. Pues o bien ponemos Object, o bien hacemos que nuestra clase Persona sea un genérico. La primera opción no es especialmente clara, porque nunca sabremos que hay dentro de datosAdicionales y si somos varios programadores, alguno puede despistarse y meter ahí cualquier cosa. Lo del genérico es un rollo, ya que obliga a casi todas las clases de nuestra librería general (paneles, daos de bd) a ser a su vez genéricos.

Y finalmente está la solución del ejemplo de WeakHashMap que había comentado y que, aunque no he probado, tiene muy buena pinta. Consiste básicamente en meter esos datos adicionales directamente en un HashMap. La clave sería nuestra clase Persona tal cual la tenemos en la librería común y el valor los datos adicionales. Podemos concretar el HashMap genérico para nuestros datos concretos HashMap<Persona, Coche> y así todo queda claro sin posibilidad de confusión. No necesitamos tocar nada de nuestra librería y podemos hacer nuestros paneles y daos de Coche por separado. Por supuesto, este WeakHashMap se guarda fuera de la clase Persona (si no, no hemos mejorado nada respecto a las soluciones anteriores) y hay que hacerlo accesible al que lo necesite.

La ventaja para este tipo de solución de un WeakHashMap frente a un HashMap normal es que el primero no se guarda referencias reales a los objetos que tiene almacenados (ni de Persona ni de Coche), por lo que si en nuestra lista de personas (que tenemos aparte) eliminamos una persona y perdemos todas las referencias a ella, el recolector de basura reclamará también la Persona y sus datos guardados en el WeakHashMap. Si lo hubiéramos metido en un HashMap normal, las referencias a Persona y Coche ahí dentro son reales, por lo que el recolector de basura no los libera. por lo que después de borrar la persona de nuestra lista de personas, debemos además acordarnos de hacer y hacer una llamada al hashmap.remove(persona). Ya sabes que un un grupo de uno o más programadores, siempre hay al menos un despistado que se olvida de estas cosas.

No veo el momento de aplicar una solución de este estilo en algún sitio, a ver si me encuentro con pegas prácticas.

Esta entrada ha sido publicada en java y etiquetada como , . Guarda el enlace permanente.

4 respuestas a WeakHashMap y una posible solución de diseño

  1. Orangel H dijo:

    Podrías, por favor, avisarme si te va bien con el «invento» y si es posible indicarme algún ejemplo? Te lo agradecería mucho, pues estoy por comenzar un desarrollo de un sistema de gestión para iglesias usando Java, y me ha parecido bastante interesante esta entrada…

  2. Pingback: de la red – 28/04/2010 « Tecnologías y su contexto

  3. ramon dijo:

    siempre puede usarse flyweight

  4. Josep dijo:

    WeakReference se utiliza en casos dónde es probable que se produzcan Memory Leaks debido a que no puedes eliminar tus referéncias (por ejemplo en una cahce). Tanto un HashMap como un WeakHashMap junto a todos sus elementos serán recolectados en el caso que expones, el peligro de usar un WeakHashMap en tu contenedor Persona es que obscura tu código (no puedes saber a ciéncia cierta que hay dentro del Hash a cada instante), no ocurre con un HashMap normal.

    La clase Persona, en el ejemplo que pones es un contenedor (final class), necesita tener todos los atributos de una persona (tenga coche o bicicleta), no es más que una representación de lo que hay en tu modelo de datos, si tu modelo de datos cambia (añades una nueva columna en la base de datos) entonces deberá cambiar tu Persona (y debe de ser así para que la versión de tu modelo de datos y tu aplicación esten sincronizadas), introducir un Map o cualquier otra estructura que mantiene atributos de forma genérica es sugar code y puede dar lugar a problemas de mantenimiento y casos de uso no testeado. Lo que me parece más lícito (si lo que buscas es no editar tu clase Persona) es mantener un Map en el que la key sea fija (Enum), de manera que no puedes introducir atributos libremente sinó que siempre estas limitado por el modelo de datos. Sin embargo abusar de Map es una mala práctica, por ello hay herramientas que pueden generar estos objetos automáticamente a partir de tu modelo de datos (por si eres prezoso).

    Early optimization is the root of much evil 😉

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.