¿Hay alguna manera de manejar colecciones anidadas de manera más elegante?

8

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.

ovdsrn
fuente
¿Qué tipo son A, By C? 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í.
dasblinkenlight
1
Sin saber algo sobre el dominio, no creo que haya una solución general. Dependiendo de cómo se usen los mapas, puede considerar reemplazar uno o más de los mapas con clases que exporten un conjunto específico de propiedades.
Ernest Friedman-Hill
44
Considere usar objetos que encapsulan el comportamiento, en lugar de estructuras de datos tontas. Cada uno de estos mapas probablemente debería estar envuelto en un objeto específico.
Además, ¿realmente necesita usar ConcurrentHashMaps en cada nivel de anidamiento?
Russell
@ ErnestFriedman-Hill: Estaba pensando que podría ser así, que no existe una "solución general", solo una relacionada con los negocios.

Respuestas:

16

Crear una clase Triplecon los campos para A, B, Integer, anulación hashCode()y equals(), y el uso Map<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.

amit
fuente
¿Explicará el votante? Asumí aquí que el OP en realidad está tratando de asignar: (A,B,Integer)-> C, y por lo tanto, el Mapuso anidado . La edición también es compatible con mi precepción.
Amit
2
Correcto, esto es lo que estoy tratando de asignar: (A, B, Integer) a C.
También agregaré, nombre a la clase Triple algo significativo en su dominio comercial. Debe significar algo :-)
Martijn Verburg
Debido al contrato de 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.
G. Bach
6

[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

Ali
fuente
Tal vez llamarlo en Triplelugar de MyClassaclarar; También hay implementaciones de n-tuplas en la web, si eres realmente vago.
En realidad, el último mapa es ConcurrentHashMap <Integer, C>, no ConcurrentHashMap <C, Integer>, pero es solo un detalle menor, ya que por su respuesta veo que lo entendió correctamente.
ovdsrn