Meine Frage ist eher eine Designfrage. In meinem Programm bin ich zu einer Datenstruktur gekommen, die ungefähr so aussieht:
private ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>> services = new ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>>();
Gibt es eine Möglichkeit, mit einer solchen Datenstruktur eleganter umzugehen? Vielen Dank!
Bearbeiten : A, B und C sind Geschäftsklassen. Eine A-Instanz "kann" (als Assoziation) viele Bs haben und ein B "kann" viele Zuordnungen Integer-C haben.
java
design
data-structures
ovdsrn
quelle
quelle
A
,B
undC
? Es wäre einfacher zu beantworten, wenn ich die Bedeutung der dreistufigen Verschachtelung Ihrer Karten verstehen könnte.ConcurrentHashMap
s auf jeder Verschachtelungsebene verwenden?Antworten:
Erstellen Sie eine Klasse
Triple
mit Feldern fürA
,B
,Integer
, überschreibenhashCode()
undequals()
, und die VerwendungMap<Triple,C>
anstelle vonMap<A,Map<B,Map<Integer,C>>>
Bei diesem Ansatz fügen Sie alle Elemente in einer Karte mit einem größeren möglichen Tastenbereich zusammen.
quelle
(A,B,Integer)
->C
und damit die verschachtelteMap
Verwendung. Die Bearbeitung unterstützt auch meine Vorahnung.equals
funktioniert dies nur, wenn die Schlüssel eine Äquivalenzbeziehung bilden. Ich bin kürzlich auf eine Situation wie diese gestoßen, in der dies nicht der Fall war: Die dritte Komponente des Schlüssels könnte entweder ein Standardwert sein, der eine beliebige Instanz akzeptiert, oder ein konkreter Wert, wobei sich alle konkreten Werte voneinander unterscheiden. Daher müsste jeder konkrete Wert als gleich dem Standardwert angesehen werden, und durch die Transitivität müssten sie alle gleich sein, was sie nicht waren.[Ich komme aus dem C # -Hintergrund, aber die Antwort sollte zutreffen]
[Es spielt keine große Rolle, aber ich gehe davon aus, dass das letzte Element ConcurrentHashMap <C, Integer> ist. ]
Sie haben eine Funktion f vom Typ A -> (B -> (C -> int)) Wenn es wirklich das ist, was Sie brauchen, habe ich keine Antwort parat. Aber vielleicht würde eine Funktion f vom Typ (A x B x C) -> int für Ihre Zwecke ausreichen.
Der Unterschied zwischen zwei Fällen besteht darin, dass der erste fauler, funktionaler, wohl eleganter ist und es möglich ist, eine "teilweise angewendete" Funktion zu haben. Zum Beispiel haben Sie ein a- Element (vom Typ A), Sie wenden a auf f an und haben eine Funktion g vom Typ (B -> (C -> int)) , die Sie weitergeben, an Methoden senden können, was auch immer. Es ist jedoch etwas umständlich und etwas mehr Code, um die Funktion richtig zu initialisieren.
Die zweite ist eifriger und weniger elegant, aber möglicherweise einfacher zu codieren und zu verstehen. Alles, was Sie tun müssen, ist eine generische Klasse Triple <A, B, C> , die Equals () und GetHashCode () überschreibt, damit sie eine Wertesemantik aufweist (zwei Instanzen sind als gleich anzusehen, wenn sie gleiche Elemente haben). und deklarieren Sie, dass die ConcurrentHashMap von Triple bis Integer ist . Die offensichtlichsten Kosten sind, dass Sie die Elemente A , B , C auf einmal bereithalten müssen, um eine Instanz von Triple zu erstellen und die Suche durchzuführen.
Bearbeiten: Wenn das letzte Element wirklich ConcurrentHashMap <C, Integer> ist , hat Ihre generische Klasse A- , B- und Integer- Felder, und die Zuordnung erfolgt von Triple <A, B, Integer> zu C.
quelle
Triple
stattMyClass
zu klären; Es gibt auch N-Tupel-Implementierungen im Web, wenn Sie wirklich faul sind.