Wie können Sie feststellen, ob Sie ein zusammengesetztes Muster, eine Baumstruktur oder eine dritte Implementierung verwenden sollen?

14

Ich habe zwei Client-Typen, einen " Observer " -Typ und einen " Subject " -Typ. Sie sind beide einer Hierarchie von Gruppen zugeordnet .

Der Beobachter erhält (Kalender-) Daten von den Gruppen, denen er in den verschiedenen Hierarchien zugeordnet ist. Diese Daten werden berechnet, indem Daten aus übergeordneten Gruppen der Gruppe kombiniert werden, die versuchen, Daten zu sammeln (jede Gruppe kann nur einen übergeordneten Benutzer haben ).

Der Betreff kann die Daten (die die Beobachter erhalten) in den Gruppen erstellen, denen er zugeordnet ist. Wenn Daten in einer Gruppe erstellt werden, verfügen auch alle "Kinder" der Gruppe über die Daten, und sie können eine eigene Version eines bestimmten Datenbereichs erstellen , die jedoch weiterhin mit den ursprünglich erstellten Daten verknüpft ist (in In meiner spezifischen Implementierung enthalten die Originaldaten Zeiträume und Überschriften, während die Untergruppen den Rest der Daten für die Empfänger angeben, die direkt mit ihren jeweiligen Gruppen verknüpft sind.

Wenn das Subjekt Daten erstellt, muss es jedoch prüfen, ob alle betroffenen Beobachter Daten haben, die im Widerspruch dazu stehen, was meines Wissens nach eine riesige rekursive Funktion bedeutet.

Ich denke, das lässt sich so zusammenfassen , dass ich in der Lage sein muss, eine Hierarchie zu haben , in der man auf und ab gehen kann , und dass einige Orte sie als Ganzes behandeln können (Rekursion, im Grunde genommen).

Außerdem strebe ich nicht nur eine Lösung an, die funktioniert. Ich hoffe, eine Lösung zu finden, die relativ einfach zu verstehen ist (zumindest in Bezug auf die Architektur) und auch flexibel genug, um in Zukunft problemlos zusätzliche Funktionen zu erhalten.

Gibt es ein Entwurfsmuster oder eine bewährte Methode, um dieses Problem oder ähnliche Hierarchieprobleme zu lösen?

EDIT :

Hier ist das Design, das ich habe: Klassendiagramm mit Methoden enthalten.  Die Klasse "Group" ist die Hierarchie

Die "Phoenix" -Klasse heißt so, weil mir noch kein passender Name eingefallen ist.

Aber außerdem muss ich in der Lage sein, bestimmte Aktivitäten für bestimmte Beobachter zu verbergen , obwohl sie über die Gruppen mit ihnen verbunden sind.


Ein wenig Off-Topic :

Ich persönlich bin der Meinung, dass ich dieses Problem auf kleinere Probleme reduzieren sollte, aber es entgeht mir, wie. Ich denke, das liegt daran, dass mehrere rekursive Funktionen, die nicht miteinander verknüpft sind, und verschiedene Client-Typen beteiligt sind, die Informationen auf unterschiedliche Weise abrufen müssen. Ich kann meinen Kopf nicht wirklich darum wickeln. Wenn jemand mich in eine Richtung leiten kann, wie ich Hierarchieprobleme besser einkapseln kann, würde ich mich sehr darüber freuen.

Aske B.
quelle
Das klingt nach einem graphentheoretischen Problem. Wir haben also einen Digraphen, der die Hierarchie der Gruppen darstellt. Jede Gruppe ist ein Eckpunkt im Diagramm. Welche Eigenschaften gelten? Stimmt es, dass es immer einen eindeutigen Scheitelpunkt nmit einem Grad von 0 gibt, während jeder andere Scheitelpunkt einen Grad von mindestens 1 hat? Ist jeder Vertex mit verbunden n? Ist der Weg zu neinzigartig? Wenn Sie die Eigenschaften der Datenstruktur auflisten und ihre Operationen auf eine Schnittstelle - eine Liste von Methoden - abstrahieren könnten, könnten wir (I) in der Lage sein, eine Implementierung dieser Datenstruktur zu finden.
Danke für Ihre Antwort. Es gibt mehrere Hierarchien von Gruppen, die nicht miteinander verbunden sind, außer durch die Beobachter, aber ich glaube nicht, dass sie Teil der Diagrammobjekte sind, sie haben nur eine Verknüpfung zu Scheitelpunkten in ihnen. Jede Gruppe in einer Hierarchie kann nur 1 übergeordnetes Element, aber 0 .. * untergeordnete Elemente haben. Wie würden Sie das in eine Grafik umsetzen? Und nur eine Hierarchie mit 1 Gruppe in wird einen In-Grad von 0 haben. Für 2-Gruppen-Hierarchien und größer werden sie alle einen gleichen In- und Out-Grad von mindestens 1 haben. Ich werde versuchen, die relevanten Methoden aufzulisten In einer Stunde, wenn ich bei der Arbeit bin.
Arbeiten die Gruppen also wie Unterklassen in C #: Sie können eine Basisklasse unterordnen, mit der Ausnahme, dass es eine Gesamtstruktur gibt (dh nicht zusammenhängende Bäume)? Wenn Sie alle Zeiger / Referenzen verbinden, haben Sie implizit bereits ein Diagramm - Sie müssen nichts weiter tun. Die Sache ist jedoch, wenn Sie Operationen wie "Befinden sich diese beiden Gruppen in derselben Hierarchie?" Effizient ausführen möchten. "Was ist der gemeinsame Vorfahr dieser beiden Gruppen?" usw. Sie müssen das Problem systematisch analysieren, um alle Dinge zu nutzen, die Sie im Voraus über die Struktur wissen.
Nun, da ich Ihr Diagramm gesehen habe, was genau ist Ihre Frage - wenn es um den Entwurfsansatz geht, kann ich Ihnen an dieser Stelle nicht wirklich helfen, da mir die verschiedenen Entwurfsmethoden selbst neu sind. Wenn Sie jedoch nach effizienten O(n)Algorithmen für eine genau definierte Datenstruktur suchen, kann ich daran arbeiten. Ich sehe, dass Sie keine Mutationsmethoden Groupund die Struktur der Hierarchien eingeführt haben. Soll ich davon ausgehen, dass diese statisch sein werden?
1
@ Malachi Ich habe keine Antwort gefunden. Leider hatte ich keine Zeit, mich eingehend damit zu befassen, und musste zu etwas anderem übergehen. Ich habe jetzt auch keine Zeit, mich damit zu befassen, aber ich werde meine Benachrichtigungen von Zeit zu Zeit überprüfen - und wenn jemand eine brauchbare Antwort gibt, werde ich sie akzeptieren.
Aske B.

Antworten:

1

Hier ist eine einfache "Gruppen" -Implementierung, mit der Sie zum Stamm navigieren und den Stamm als Sammlung durchsuchen können.

public class Group
{
  public Group Parent
  public List<Group> Children

  public IEnumerable<Group> Parents()
  {
    Group result = this;
    while (result.Parent != null)
    {
      result = result.Parent;
      yield return result;
    }
  }
  public Group Root()
  {
    return Parents.LastOrDefault() ?? this;
  }


  public IEnumerable<Group> WalkTreeBreadthFirst(
  {
    //http://en.wikipedia.org/wiki/Breadth-first_search
    HashSet<Group> seenIt = new HashSet<Group>()
    Queue<Group> toVisit = new Queue<Group>();
    toVisit.Enqueue(this);

    while (toVisit.Any())
    {
      Group item = toVisit.Dequeue();
      if (!seenIt.Contains(item))
      {
        seenIt.Add(item);
        foreach (Group child in item.Children)
        {
          toVisit.Enqueue(child);
        }
        yield return item;
      }
    }
  }

  public static IEnumerable<Group> WalkTreeDepthFirst()
  {
    // http://en.wikipedia.org/wiki/Depth-first_search
    HashSet<Group> seenIt = new HashSet<Group>();
    Stack<Group> toVisit = new Stack<Group>();

    toVisit.Push(this);

    while (toVisit.Any())
    {
      Group item = toVisit.Pop();
      if (!seenIt.Contains(item))
      {
        seenIt.Add(item);
        foreach (Group child in item.Children.Reverse())
        {
          toVisit.Push(child);
        }
        yield return item;
      }
    }
  }
}

Wenn Sie also eine Gruppe haben, können Sie den Baum dieser Gruppe gehen:

Group myGroup = GetGroup();
Group root = myGroup.Root;
foreach(Group inTree in root.WalkTreeBreadthFirst())
{
  //do something with inTree Group.
}

Ich hoffe, dass Sie beim Posten dieses Dokuments zeigen können, wie Sie in einem Baum navigieren (und dessen Komplexität beseitigen), dass Sie in der Lage sind, die Vorgänge zu visualisieren, die Sie an dem Baum ausführen möchten, und die Muster dann selbst überprüfen, um sie anzuzeigen was am besten gilt.

Amy B
quelle
0

Aufgrund der eingeschränkten Sicht auf die Nutzungs- oder Implementierungsanforderungen Ihres Systems ist es schwierig, zu spezifisch zu werden. Zum Beispiel könnten folgende Dinge in Betracht kommen:

  • Ist das System sehr zeitgleich (viele Benutzer)?
  • Wie ist das Lese- / Schreibverhältnis beim Datenzugriff? (High Read, Low Write ist üblich)

Bei Mustern usw. würde ich mich weniger darum kümmern, welche genauen Muster in Ihrer Lösung auftreten, sondern vielmehr um das Design der tatsächlichen Lösung. Ich halte Kenntnisse über Entwurfsmuster für nützlich, aber nicht für das A und O: Um eine Schriftstelleranalogie zu verwenden, sind Entwurfsmuster eher ein Wörterbuch häufig verwendeter Phrasen als ein Wörterbuch von Sätzen, in dem Sie ein ganzes Buch schreiben müssen von.

Ihr Diagramm sieht für mich im Allgemeinen in Ordnung aus.

Es gibt einen Mechanismus, den Sie nicht erwähnt haben und der darin besteht, eine Art Cache in Ihrer Hierarchie zu haben. Natürlich müssen Sie dies mit großer Sorgfalt umsetzen, aber es könnte die Leistung Ihres Systems erheblich verbessern. Hier ist eine einfache Einstellung (Vorbehalt Emptor):

Speichern Sie für jeden Knoten in Ihrer Hierarchie geerbte Daten mit dem Knoten. Tun Sie dies faul oder proaktiv, das liegt an Ihnen. Wenn die Hierarchie aktualisiert wird, können Sie entweder die Cache-Daten für alle betroffenen Knoten dort und danach neu generieren oder an den entsprechenden Stellen "Dirty" -Flags setzen und die betroffenen Daten bei Bedarf träge neu generieren.

Ich habe keine Ahnung, wie angemessen dies in Ihrem System ist, kann aber eine Überlegung wert sein.

Auch diese Frage zu SO kann relevant sein:

/programming/1567935/how-to-do-inheritance-modeling-in-relational-databases

Occulus
quelle
0

Ich weiß, dass dies ein bisschen offensichtlich ist, aber ich werde es trotzdem sagen. Ich denke, Sie sollten einen Blick darauf werfen Observer Pattern , dass Sie erwähnt haben, dass Sie einen Beobachter-Typ haben, und was Sie haben, sieht für mich wie das Beobachter-Muster aus.

ein paar links:

DoFactory

oodesign

check die aus. Andernfalls würde ich einfach das, was Sie in Ihrem Diagramm haben, codieren und dann das Entwurfsmuster verwenden, um es bei Bedarf zu vereinfachen. Sie wissen bereits, was passieren muss und wie das Programm funktionieren soll. Schreiben Sie einen Code und prüfen Sie, ob er noch passt.

Malachi
quelle