En el proyecto en el que estoy trabajando actualmente teníamos tres tipos diferentes de precios según la edad del usuario (adulto, niño, etc.). Así que teníamos en la base de datos una tabla con este aspecto:
PRICES type Amount A 20 B 15 C .. D ..
Al principio solo teníamos 4 tipos diferentes de precios, así que en el código, teníamos algo como esto:
Map<String, BigDecimal> prices = new HashMap<String, BigDecimal>();
Donde las claves eran el tipo de precio.
Recientemente, agregaron una nueva regla comercial que agrega 3 subtipos a cada tipo de precio, por lo que ahora tenemos algo como esto:
PRICES type subtype Amount A 1 20 A 2 15 A 3 .. B 1 .. B 2 .. ... .. ..
¿Cuál de las siguientes dos opciones crees que es mejor y por qué?
Mapas anidados
Map<String, Map<String, BigDecimal>> prices;
donde las claves son el tipo de precio y el subtipo:
prices.get(type).get(subtype);
Llaves combinadas
El mismo mapa que originalmente:
Map<String, BigDecimal> prices;
Y concatene las claves para indexar los diferentes precios:
prices.get(type+"_"+subtype);
java
data-structures
mario595
fuente
fuente
class PriceKey{ PriceType type; PriceSubtype subtype; }
llave. Esto se puede extender fácilmente aún másRespuestas:
Ambas teclas anidadas y combinadas tienen sus lugares. bowmore da un argumento pro para claves compuestas, y un argumento en contra para mapas anidados. Permítanme proporcionar la oposición leal:
Las teclas de mapa compuestas funcionan muy bien cuando busca un elemento conocido específico.
Los mapas anidados funcionan bien cuando necesita encontrar rápidamente todas las variaciones, tipos y subtipos de tipo A. Por ejemplo, elegir A (vs. B, C, ...) podría ser el primer paso en un árbol de decisión. Una vez que el usuario o el algoritmo o lo que sea que elija A, solo necesita saber acerca de los subtipos de A, y B..Z o B..ZZZZZ ya no importan.
Ahora se trata de una estructura de búsqueda muy ajustada y eficiente para la búsqueda secundaria. Si intentas hacer eso con teclas compuestas, terminas haciendo un escaneo completo de la tabla a la
[ (key, value) for (key, value) in prices.items() if key.startswith('A') ]
. Esa no es una operación eficiente, y será lenta si el mapa es bastante grande.Los mapas anidados también funcionan bien cuando puede aumentar el número de niveles de anidación. La estructura del problema ya se extendió de
type
a(type, subtype)
. ¿Hay alguna posibilidad de que la próxima revolución necesite(type, subtype, variation)
o(type, subtype, version)
? Si es así, un enfoque de mapeo anidado se puede extender limpiamente. Esto, sin embargo, es una ventaja estilística de segundo orden, especialmente en comparación con la ventaja de "búsqueda fácil" anterior.fuente
key.startswith('RXR')
pruebas que mencioné. Los mapas anidados son siempre operaciones O (1), y no requieren la sobrecarga de ordenar previamente el mapa, o comparaciones de cadenas.Evita los mapas anidados. Son más difíciles de escalar y conducen a un código que es muy detallado y difícil de leer con todas las declaraciones genéricas anidadas.
Más importante aún, los mapas en Java tienden a consumir mucha memoria. Llenar un mapa con aún más mapas solo agravará el problema del consumo de memoria.
Por último, un Mapa que usa claves compuestas es más fácil de razonar.
El uso de teclas compuestas facilitará su vida en los casos más típicos, aunque algunas cosas serán más difíciles. Obtener todos los precios de un componente clave específico, por ejemplo, pero es más probable que consulte ese resultado directamente desde la base de datos en lugar de destilarlo desde el Mapa.
fuente
Esto tiene menos que ver con "qué implementación es la mejor" y más con "con qué abstracción debería estar trabajando".
Tanto la clave compuesta como el mapa de mapas tienen sus puntos fuertes y sus puntos débiles, todos los cuales residen en el dominio del rendimiento (es decir, velocidad / uso de memoria). No difieren en su funcionalidad: ambos toman dos valores y devuelven el valor "puesto" previamente.
Como son funcionalmente equivalentes, lo primero que debe hacer es hacer un resumen sobre ellos. No te preocupes por cuál es mejor. Cree una interfaz DoubleKeyedMap con todos los métodos que necesita y úsela en su código. Luego escriba cualquier implementación que pueda escribir más rápido y simplemente continúe.
SOLO una vez que haya escrito su aplicación y haya descubierto que su implementación de clave compuesta no se filtra en la primera clave muy rápido, o que el mapa de mapas está tomando demasiada memoria en caso de que vaya y optimice.
La optimización prematura es la raíz de todo mal. No abstraer es peor.
fuente
Ambas opciones no son buenas en mi opinión. ¿Qué sucede si la lógica de negocios cambia nuevamente para que tenga otro subtipo?
Lo que te sugiero que hagas es lo siguiente:
Type
esta tabla como se veríaType(INT auto_inc id, VARCHAR(255) name, VARCHAR(255) desc, INT status, etc)
Price
tabla, use la clave externa de laType
tabla de arriba para que se vea comoPrice(INT type_id, INT price)
inactive
porque las referencias colgantes harían que la eliminación sea un verdadero dolor de cabezaAhora, la lógica de usuario y de negocio puede agregar cualquier combinación de subtipo de tipo al esquema. Lo que tendrían que hacer es simplemente crear una nueva fila en la
Type
tabla y cambiarname
y / odesc
en la tabla anterior.En su caso, el usuario cambiaría el nombre de tipo
A
por tipoA_1
, agregaría un nuevo tipo llamadoA_2
y establecería un nuevo precioA_2
como15
fuente