4 Stimmen

Welches Entwurfsmuster?

Ich habe eine Klasse A, die eine Liste von Objekten der Klasse B verwaltet. Aber jedes Objekt der Klasse B kann in jedem Objekt der Klasse A referenziert werden. Die Klasse B verwaltet auch eine Liste von Objekten der Klasse A, in der sie referenziert wird. Das Programm kann und wird (mehrere) Objekte sowohl der Klasse A als auch der Klasse B "nach Belieben" erstellen und auch löschen.

Wenn ich C# verwende, kann ich Objekte aus beiden Klassen mit folgendem Code hinzufügen und löschen

public class A
{
    private List<B>ListOfObjects_B;
    public bool Add(B Object)
    {
       bool bAdd = false;
       if ((Object != null) && (ListOfObjects_B.IndexOf(B) <0))
       {
          ListOfObjects_B.Add(Object);
          Object.Add(this);
          bAdded = true;
       }
       return bAdded;
    }

    public bool Delete(B Object)
    {
       bool bDeleted = ListOfObjects_B.Remove(Object);
       if (bDeleted == true) Object.Delete(this);
       return bDeleted;
    }
}

public class B
{
    private List<A>ListOfObjects_A;
    public bool Add(A Object)
    {
        bool bAdd = false;
        if ((Object != null) && (ListOfObjects_A.IndexOf(A) <0))
        {
            ListOfObjects_A.Add(Object);
            Object.Add(this);
            bAdded = true;
        }
        return bAdded;
   }

   public bool Delete(A Object)
   {
       bool bDeleted = ListOfObjects_A.Remove(Object);
       if (bDeleted == true) Object.Delete(this);
       return bDeleted;
   }
}

Dies wird funktionieren, da durch das Entfernen/Hinzufügen des Objekts in die ListOfObjects beim ZWEITEN Mal (durch Rekursion) die Funktion aufgerufen wird und das Löschen/Hinzufügen fehlschlägt, wodurch eine Endlosschleife vermieden wird.

Aber ich mag diesen Code nicht, auch wenn A und B nicht viel über die andere Klasse wissen und nur eine Delete/Add-Funktion aufrufen.

Ich nehme an, diese Art von Problem ist allgemein und es gibt ein Entwurfsmuster, um es so zu behandeln, dass eine Rekursion vermieden werden kann und die Aktualisierung beider Listen "einfach besser" ist. Welches Entwurfsmuster sollte ich verwenden? Ich würde es begrüßen, wenn Sie auch etwas Code hinzufügen würden.

0 Stimmen

Zu Ihrem Kommentar (Antwort auf meine nachstehende Antwort): Ich denke, man kann die von Ihnen beschriebene Situation (mehrere verschiedene Assoziationen zwischen Klassenpaaren) durch Parametrisierung (über Typparameter) der Klasse AssocationTable behandeln. So hätten Sie AssociationTable<A,B> für A-B-Paare und AssociationTable<C,D> für C-D-Paare, usw.

4voto

Itay Maman Punkte 29121

Man kann die Sache vereinfachen, indem man die "Objektzuordnung" in eine eigene Klasse verschiebt. Hier ist, was ich im Sinn habe.

Definieren Sie eine Klasse namens AssociationTable. Diese Klasse wird eine Liste von Paaren verwalten, wobei jedes Paar einen Verweis auf ein A-Objekt und einen Verweis auf ein B-Objekt enthält.

Jedes A-Objekt (und jedes B-Objekt) enthält einen Verweis auf das AssociationTable-Objekt. A.Add(B) wird als table.add(this, b) implementiert; B.Add(A) wird als table.add(a, this) implementiert;

Der Löschvorgang wird als table.delete(this, b) oder table.delete(a, this) ausgeführt.

class Pair { 
  A a; B b; 
  Pair(A a, B b) { this.a = a; this.b = b; } 
  // Also override Equals(), HashCode()
}

class AssociationTalbe {
  Set<Pair> pairs = ...;

  void add(A a, B b) { pairs.add(new Pair(a, b)); }
  void remove(A a, B b) { pairs.remove(new Pair(a, b)); }
}

class A {
  AssociationTable table;

  public A(AssociationTable t) { table = t; }

  void add(B b) { table.add(this, b); }
  void remove(B b) { table.remove(this, b); }
}

Bearbeiten: Das Problem bei diesem Design ist die Garbage Collection. Die Tabelle enthält Verweise auf Objekte und unterdrückt so deren Sammlung. In Java könnten Sie ein WeakReference-Objekt verwenden, um dieses Problem zu lösen. Ich bin mir ziemlich sicher, dass es etwas ähnliches in der .Net Welt gibt

Außerdem könnte die Tabelle ein Singleton sein. Ich mag Singletons nicht allzu sehr. In diesem Fall macht ein Singleton die A-B-Verknüpfung in Ihrem Programm eindeutig. Das kann etwas sein, das unerwünscht ist, aber es hängt von Ihren konkreten Bedürfnissen ab.

Schließlich (um die Dinge in den richtigen Kontext zu stellen) funktioniert dieses Design genauso wie Many-to-Many-Beziehungen in relationalen Datenbanken.

2voto

Thomas Levesque Punkte 277723

Ich schrieb kürzlich eine Klasse zur Behandlung eines ähnlichen Problems . Es handelt sich eigentlich um ein einfacheres Szenario (Eltern-Kind-Beziehung, wobei die Kinder auf ihre Eltern verweisen), aber Sie könnten es wahrscheinlich für Ihre Bedürfnisse anpassen. Der Hauptunterschied besteht darin, dass die Parent Eigenschaft in meiner Implementierung sollte durch eine Sammlung von Eltern ersetzt werden.

1voto

mnuzzo Punkte 3381

Das Einzige, was mir einfällt, ist die Verwendung eines Mediator-Musters, damit sich A nicht zu B hinzufügt:

public class Mediator {

    public void Add(A List, B Object) {
        if(list.Add(Object)) {
            object.Add(List);
        }
    }

    public void Delete(A List, B Object) {
        if(List.Delete(Object)) {
            Object.Delete(List);
        }
    }
}

Danach würden Sie die Codezeilen entfernen, die lauten "Object.Add(this);" und "if (bDeleted == true) Object.Delete(this);" Dies hat auch den Vorteil, dass die Anzahl der Aufrufe der einzelnen Methoden reduziert wird, da zuvor die Methoden von Objekt A zweimal aufgerufen wurden, da Objekt B diese Methoden auch für Objekt A aufrief.

EDIT: Bei näherer Betrachtung wurde mir klar, dass Sie in gewisser Weise bereits ein Observer-Entwurfsmuster verwenden. Objekt A ist der Beobachter und Objekt B ist das zu beobachtende Objekt. Objekt A verwaltet eine Liste von Objekten, die es beobachtet, und Objekt B verwaltet eine Liste von Objekten, die es beobachten. Das Einzige, was ich nicht sehe, ist eine zusätzliche Funktionalität, obwohl es wahrscheinlich eine gibt. Grundsätzlich wird Objekt B allen Objekten A, die es beobachten, mitteilen, dass es sich geändert hat, und alle diese Objekte A werden nach der Änderung fragen. Wenn es das ist, was Sie suchen, müssen Sie nur die Zeilen "Object.Add(this);" und "if(bDeleted == true) Object.Delete(this);" aus dem B-Code entfernen, da sie unnötig sind.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X