Mi pregunta es más bien una pregunta de diseño. En mi programa llegué a una estructura de datos que se parece a esto:
private ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>> services = new ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>>();
¿Hay alguna manera de manejar esa estructura de datos de manera más elegante? ¡Gracias!
editar : A, B y C son clases de negocios. Una instancia A "puede tener" (como asociación) muchos Bs y una B "puede tener" muchas asignaciones Integer-C.
java
design
data-structures
ovdsrn
fuente
fuente
A
,B
yC
? Sería más fácil responder si pudiera entender el significado de la anidación de tres niveles de sus mapas de has allí.ConcurrentHashMap
s en cada nivel de anidamiento?Respuestas:
Crear una clase
Triple
con los campos paraA
,B
,Integer
, anulaciónhashCode()
yequals()
, y el usoMap<Triple,C>
en lugar deMap<A,Map<B,Map<Integer,C>>>
En este enfoque, coloca todos los elementos en un mapa, con un mayor rango posible de claves.
fuente
(A,B,Integer)
->C
, y por lo tanto, elMap
uso anidado . La edición también es compatible con mi precepción.equals
, esto solo funcionará si las claves forman una relación de equivalencia. Recientemente me encontré con una situación como esta en la que no lo hicieron: el tercer componente de la clave podría ser un valor predeterminado que aceptaría cualquier instancia, o algún valor concreto, con todos los valores concretos diferentes entre sí. Por lo tanto, cualquier valor concreto tendría que considerarse igual al valor predeterminado, y por transitividad, todos tendrían que ser iguales entre sí, lo que no eran.[Vengo de C # de fondo, pero la respuesta debería aplicarse]
[No importa mucho, pero supongo que el último elemento es ConcurrentHashMap <C, Integer> ]
Tiene una función f de tipo A -> (B -> (C -> int)) Si realmente es lo que necesita, no tengo una respuesta lista. Pero tal vez, tener una función f de tipo (A x B x C) -> int sería suficiente para sus propósitos.
La diferencia entre dos casos es que el primero es más vago, más funcional, posiblemente más elegante y es posible tener una función "parcialmente aplicada". Por ejemplo, tiene un elemento a (de tipo A), aplica a a f y tiene una función g de tipo (B -> (C -> int)) para pasar, enviar a métodos, lo que sea. Sin embargo, es un poco engorroso y un poco más de código para inicializar correctamente la función.
El segundo es más entusiasta y menos elegante, pero puede ser más fácil de codificar y comprender. Todo lo que necesita hacer es tener una clase genérica Triple <A, B, C> , anular Equals () y GetHashCode () para que tenga semántica de valor (dos instancias deben considerarse iguales si tienen elementos iguales) y declarar que el ConcurrentHashMap es de Triple a Entero . El costo de pago más obvio es que necesita tener los elementos A , B , C listos de una vez para crear una instancia de Triple y realizar la búsqueda.
Editar: Si el último elemento es realmente ConcurrentHashMap <C, Integer> , su clase genérica tendrá campos A , B e Integer , y la asignación será de Triple <A, B, Integer> a C
fuente
Triple
lugar deMyClass
aclarar; También hay implementaciones de n-tuplas en la web, si eres realmente vago.