Angenommen, ich habe zwei Objekttypen, A und B. Die Beziehung zwischen ihnen ist viele-zu-viele, aber keiner von ihnen ist der Besitzer des anderen.
Sowohl A- als auch B-Instanzen müssen sich der Verbindung bewusst sein. Es ist nicht nur ein Weg.
Also können wir das tun:
class A
{
...
private: std::vector<B *> Bs;
}
class B
{
private: std::vector<A *> As;
}
Meine Frage ist: Wo platziere ich die Funktionen zum Erstellen und Zerstören der Verbindungen?
Sollte es A :: Attach (B) sein, das dann die Vektoren A :: Bs und B :: As aktualisiert?
Oder sollte es B :: Attach (A) sein, was ebenso vernünftig erscheint.
Keiner von beiden fühlt sich richtig an. Wenn ich aufhöre, mit dem Code zu arbeiten, und nach einer Woche zurückkomme, kann ich mich sicher nicht erinnern, ob ich A.Attach (B) oder B.Attach (A) ausführen soll.
Vielleicht sollte es eine Funktion wie diese sein:
CreateConnection(A, B);
Das Erstellen einer globalen Funktion erscheint jedoch auch unerwünscht, da es sich um eine Funktion handelt, die speziell für die Arbeit mit nur den Klassen A und B vorgesehen ist.
Eine andere Frage: Wenn ich häufig auf dieses Problem / diese Anforderung stoße, kann ich dann irgendwie eine allgemeine Lösung dafür finden? Vielleicht eine TwoWayConnection-Klasse, die ich von Klassen ableiten oder in Klassen verwenden kann, die diese Art von Beziehung teilen?
Was sind einige gute Möglichkeiten, um mit dieser Situation umzugehen ... Ich weiß, wie man mit der Eins-zu-Viele-Situation "C besitzt D" recht gut umgeht, aber diese ist schwieriger.
Bearbeiten: Nur um es deutlicher zu machen, beinhaltet diese Frage keine Eigentumsfragen. Sowohl A als auch B gehören einem anderen Objekt Z, und Z kümmert sich um alle Eigentumsfragen. Ich bin nur daran interessiert, wie man die vielen-zu-vielen-Verknüpfungen zwischen A und B erstellt / entfernt.
Pointer
undGestureRecognizer
. Zeiger gehören der InputManager-Klasse und werden von ihr verwaltet. GestureRecognizers gehören Widget-Instanzen, die wiederum einer Screen-Instanz gehören, die einer App-Instanz gehört. Zeiger werden GestureRecognizern zugewiesen, damit sie ihnen rohe Eingabedaten zuführen können. GestureRecognizer müssen jedoch wissen, wie viele Zeiger derzeit mit ihnen verknüpft sind (um zwischen 1-Finger- und 2-Finger-Gesten usw. zu unterscheiden).Antworten:
Eine Möglichkeit besteht darin , jeder Klasse eine öffentliche
Attach()
Methode sowie eine geschützteAttachWithoutReciprocating()
Methode hinzuzufügen . Machen SieA
undB
gemeinsame Freunde, damit ihreAttach()
Methoden die des anderen anrufen könnenAttachWithoutReciprocating()
:Wenn Sie ähnliche Methoden für implementieren
B
, müssen Sie sich nicht merken, welche Klasse aufgerufen werden sollAttach()
.Ich bin sicher, Sie könnten dieses Verhalten in eine
MutuallyAttachable
Klasse einwickeln, die beides istA
und von der SieB
erben, und so vermeiden, sich zu wiederholen und am Tag des Jüngsten Gerichts Bonuspunkte zu sammeln. Aber auch der unkomplizierte Ansatz, es an beiden Orten zu implementieren, wird die Arbeit erledigen.quelle
MutuallyAttachable
Klasse, die ich für diese Aufgabe geschrieben habe, wenn jemand sie wiederverwenden möchte: goo.gl/VY9RB (Pastebin) Bearbeiten: Dieser Code könnte verbessert werden, indem er zu einer Vorlagenklasse gemacht wird.MutuallyAttachable<T, U>
Klassenvorlage bei Gist platziert. gist.github.com/3308058Kann die Beziehung selbst zusätzliche Eigenschaften haben?
Wenn ja, sollte es eine separate Klasse sein.
Wenn nicht, reicht jeder Mechanismus zur Verwaltung der hin- und hergehenden Listen aus.
quelle
Normalerweise, wenn ich in Situationen wie diese gerate, die sich unangenehm anfühlen, aber ich kann nicht genau sagen warum, weil ich versuche, etwas in die falsche Klasse zu bringen. Es gibt fast immer eine Möglichkeit, einige Funktionen aus dem Unterricht zu entfernen
A
undB
die Dinge klarer zu machen.Ein Kandidat für das Verschieben der Zuordnung ist der Code, der die Zuordnung überhaupt erst erstellt. Vielleicht
attach()
speichert statt es einfach eine Liste vonstd::pair<A, B>
. Wenn mehrere Stellen Assoziationen erzeugen, kann diese in eine Klasse abstrahiert werden.Ein weiterer Kandidat für einen Umzug ist
Z
in Ihrem Fall das Objekt, dem die zugehörigen Objekte gehören .Ein weiterer häufiger Kandidat für das Verschieben der Zuordnung ist der Code, der häufig Methoden oder Objekte aufruft . Anstatt beispielsweise aufzurufen , was intern etwas mit allen zugeordneten Objekten tut , kennt es bereits die Zuordnungen und ruft für jedes einzelne auf. Wenn es an mehreren Stellen aufgerufen wird, kann es wiederum in eine einzelne Klasse abstrahiert werden.
A
B
a->foo()
B
a->foo(b)
Oft sind die Objekte, die die Zuordnung erstellen, besitzen und verwenden, dasselbe Objekt. Das kann das Refactoring sehr einfach machen.
Die letzte Methode besteht darin, die Beziehung aus anderen Beziehungen abzuleiten. Zum Beispiel sind Brüder und Schwestern eine Viele-zu-Viele-Beziehung, aber anstatt eine Liste der Schwestern in der Bruderklasse zu führen und umgekehrt, leiten Sie diese Beziehung aus der elterlichen Beziehung ab. Der andere Vorteil dieser Methode ist, dass sie eine einzige Quelle der Wahrheit schafft. Es gibt keine Möglichkeit für einen Fehler oder Laufzeitfehler, eine Diskrepanz zwischen der Bruder-, Schwester- und Elternliste zu erstellen, da Sie nur eine Liste haben.
Diese Art des Refactorings ist keine Zauberformel, die jedes Mal funktioniert. Sie müssen noch experimentieren, bis Sie für jeden einzelnen Umstand eine gute Passform gefunden haben, aber ich habe festgestellt, dass dies in etwa 95% der Fälle funktioniert. Die verbleibenden Zeiten muss man nur mit der Unbeholfenheit leben.
quelle
Wenn ich dies implementieren würde, würde ich Attach sowohl in A als auch in B einfügen. Innerhalb der Attach-Methode würde ich dann Attach für das übergebene Objekt aufrufen. Auf diese Weise können Sie entweder A.Attach (B) oder B.Attach ( EIN). Meine Syntax ist möglicherweise nicht korrekt. Ich habe C ++ seit Jahren nicht mehr verwendet:
Eine alternative Methode wäre, eine 3. Klasse C zu erstellen, die eine statische Liste von AB-Paaren verwaltet.
quelle