Existe uma maneira de lidar com coleções aninhadas de maneira mais elegante?

8

Minha pergunta é bastante uma questão de design. No meu programa, cheguei a uma estrutura de dados que se parece com isso:

private ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>> services  = new ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>>();

Existe uma maneira de lidar com essa estrutura de dados de maneira mais elegante? Obrigado!

editar : A, B e C são classes de negócios. Uma instância A "pode ​​ter" (como associação) muitos Bs e um B "pode ​​ter" muitos mapeamentos Integer-C.

ovdsrn
fonte
Que tipos são A, Be C? Seria mais fácil responder se eu pudesse entender o significado do aninhamento em três níveis dos seus mapas lá.
precisa saber é o seguinte
1
Sem saber algo sobre o domínio, não acho que exista uma solução geral. Dependendo de como os mapas estão sendo usados, considere substituir um ou mais mapas por classes que exportam um conjunto específico de propriedades.
Ernest Friedman-Hill
4
Considere usar objetos que encapsulam o comportamento, em vez de estruturas de dados idiotas. Cada um desses mapas provavelmente deve ser agrupado em um objeto específico.
Como um aparte, você realmente precisa usar ConcurrentHashMaps em todos os níveis de aninhamento?
Russell Russell
@ ErnestFriedman-Hill: Eu estava pensando que poderia ser assim - que não há "solução geral", apenas uma relacionada a negócios.

Respostas:

16

Crie uma classe Triplecom campos para A, B, Integer, override hashCode()e equals()e uso Map<Triple,C>, em vez deMap<A,Map<B,Map<Integer,C>>>

Nesta abordagem - você coloca todos os elementos em um mapa, com um maior número possível de chaves.

amit
fonte
O downvoter vai explicar? Presumi aqui que o OP realmente está tentando mapear: (A,B,Integer)-> Ce, portanto, o Mapuso aninhado . A edição também suporta minha precepção.
13323 amit
2
Correto, é isso que eu estou tentando mapear: (A, B, Integer) para C.
Além disso, adicionarei o nome de classe tripla como algo significativo em seu domínio comercial. Deve significar alguma coisa :-)
Martijn Verburg
Por causa do contrato de equals, isso só funcionará se as chaves formarem uma relação de equivalência. Recentemente, encontrei uma situação como essa em que não: o terceiro componente da chave poderia ser um valor padrão que aceitaria qualquer instância ou algum valor concreto, com todos os valores concretos sendo diferentes um do outro. Assim, qualquer valor concreto teria que ser considerado igual ao padrão e, por transitividade, todos teriam que ser iguais um ao outro, o que não eram.
G. Bach
6

[Eu venho de background em C #, mas a resposta deve ser aplicada]

[Não importa muito, mas presumo que o último item seja ConcurrentHashMap <C, Inteiro> ]

Você tem uma função f do tipo A -> (B -> (C -> int)). Se é realmente o que você precisa, não tenho uma resposta pronta. Mas talvez, ter uma função f do tipo (A x B x C) -> int seja suficiente para seus propósitos.

A diferença entre dois casos é que o primeiro é mais preguiçoso, mais funcional, sem dúvida mais elegante e é possível ter uma função "parcialmente aplicada". Por exemplo, você tem uma um (do tipo A) elemento, você aplicar um para f e têm uma função g do tipo (B -> (C -> int)) para passar ao redor, enviar para métodos, seja qual for. No entanto, é um pouco complicado e um pouco mais de código para inicializar corretamente a função.

O segundo é mais ávido e menos elegante, mas pode ser mais fácil codificar e entender. Tudo que você precisa fazer é ter uma classe genérica Triple <A, B, C> , substituir Equals () e GetHashCode () para que ela tenha semântica de valor (duas instâncias serão consideradas iguais se tiverem elementos iguais) e declare que o ConcurrentHashMap é de Triplo para Inteiro . O custo mais óbvio a pagar é que você precisa ter os elementos A , B , C prontos de uma só vez para criar uma instância do Triple e executar a pesquisa.

Edit: Se o último item for realmente ConcurrentHashMap <C, Inteiro> , sua classe genérica terá campos A , B e Inteiro , e o mapeamento será de Triplo <A, B, Inteiro> para C

Todos
fonte
Talvez chame em Triplevez de MyClassesclarecer; também existem implementações de n-tupla na web, se você é realmente preguiçoso.
Na verdade, o último mapa é ConcurrentHashMap <Inteiro, C>, não ConcurrentHashMap <C, Inteiro>, mas é apenas um pequeno detalhe, pois, pela sua resposta, vejo que você entendeu corretamente.
ovdsrn