Come si può sapere se utilizzare il modello composito o una struttura ad albero o una terza implementazione?


14

Ho due tipi di client, un tipo " Observer " e un tipo " Oggetto ". Sono entrambi associati a una gerarchia di gruppi .

L'Osservatore riceverà (calendario) i dati dai gruppi a cui è associato attraverso le diverse gerarchie. Questi dati vengono calcolati combinando i dati dei gruppi "parent" del gruppo che tentano di raccogliere dati (ogni gruppo può avere un solo parent ).

Il Soggetto sarà in grado di creare i dati (che gli Osservatori riceveranno) nei gruppi a cui sono associati. Quando i dati vengono creati in un gruppo, anche tutti i "figli" del gruppo avranno i dati e saranno in grado di creare la propria versione di un'area specifica dei dati , ma comunque collegata ai dati originali creati (in la mia specifica implementazione, i dati originali conterranno periodi di tempo e titolo, mentre i sottogruppi specificano il resto dei dati per i destinatari direttamente collegati ai rispettivi gruppi).

Tuttavia, quando il Soggetto crea dati, deve verificare se tutti gli Osservatori interessati hanno dati in conflitto con questo, il che significa un'enorme funzione ricorsiva, per quanto posso capire.

Quindi penso che questo possa essere riassunto al fatto che ho bisogno di essere in grado di avere una gerarchia in cui puoi andare su e giù , e alcuni posti sono in grado di trattarli nel loro insieme (ricorsione, in sostanza).

Inoltre, non sto solo mirando a una soluzione che funzioni. Spero di trovare una soluzione che sia relativamente facile da capire (almeno per quanto riguarda l'architettura) e anche abbastanza flessibile da poter ricevere facilmente funzionalità aggiuntive in futuro.

Esiste un modello di progettazione o una buona pratica da seguire per risolvere questo problema o problemi di gerarchia simili?

MODIFICA :

Ecco il design che ho: Diagramma di classe con metodi inclusi.  La classe "Gruppo" è la gerarchia

La classe "Phoenix" è chiamata così perché non pensavo ancora a un nome appropriato.

Ma oltre a ciò, devo essere in grado di nascondere attività specifiche per osservatori specifici , anche se sono collegati ad essi attraverso i gruppi.


Un po 'fuori tema :

Personalmente, sento che dovrei essere in grado di ridurre questo problema a problemi più piccoli, ma mi sfugge come. Penso che sia perché comporta molteplici funzionalità ricorsive che non sono associate tra loro e diversi tipi di client che devono ottenere informazioni in modi diversi. Non posso davvero avvolgerci la testa. Se qualcuno può guidarmi in una direzione su come migliorare l'incapsulamento dei problemi della gerarchia, sarei molto felice di ricevere anche quello.


Sembra un problema di teoria dei grafi. Quindi abbiamo qualche digrafo che rappresenta la gerarchia dei gruppi. Ogni gruppo è un vertice nel grafico. Quali proprietà sono vere? È vero che esiste sempre un vertice univoco ncon un in-gradi di 0 mentre ogni altro vertice ha un in-gradi di almeno 1? Ogni vertice è collegato n? Il percorso è nunico? Se potessi elencare le proprietà della struttura dei dati e astrarre le sue operazioni su un'interfaccia - un elenco di metodi - noi (I) potremmo essere in grado di elaborare un'implementazione di detta struttura di dati.

Grazie per la vostra risposta. Esistono più gerarchie di gruppi che non sono collegate l'una all'altra, tranne che attraverso gli osservatori, ma non penso che facciano parte degli oggetti grafici, hanno solo un collegamento ai vertici in essi. Ogni gruppo in una gerarchia può avere solo 1 genitore, ma 0 .. * figli. Come lo implementeresti in un grafico? E solo una gerarchia con 1 gruppo in avrà un in-gradi di 0. Per gerarchie di 2 gruppi e più grandi avranno tutti un uguale in e out-grado di almeno 1. Proverò a elencare i suoi metodi pertinenti tra un'ora, quando sarò al lavoro.

Quindi i gruppi funzionano esattamente come la sottoclasse in C #: puoi sottoclassare una classe base, con l'eccezione che esiste una foresta (cioè alberi disgiunti)? Bene, se colleghi tutti i puntatori / riferimenti, allora implicitamente hai già un grafico: non devi fare altro. Il fatto è, tuttavia, se si desidera eseguire in modo efficiente operazioni come "Questi due gruppi si trovano nella stessa gerarchia?" "Qual è l'antenato comune per questi due gruppi?" ecc. è necessario analizzare il problema in modo sistematico per sfruttare tutte le cose che si conoscono in anticipo sulla struttura.

Ora che ho visto il tuo diagramma, qual è esattamente la tua domanda - se si tratta dell'approccio di progettazione, non posso davvero aiutarti a questo punto, dato che sono nuovo delle varie metodologie di progettazione, me stesso. Tuttavia, se stai cercando O(n)algoritmi efficienti per una struttura di dati ben definita, posso lavorarci su. Vedo che non hai messo in atto alcun metodo mutante Groupe la struttura delle gerarchie. Devo presumere che questi saranno statici?

1
@Malachi Non ho trovato una risposta. Purtroppo non ho avuto il tempo di indagare a fondo e ho dovuto passare a qualcos'altro. Non ho nemmeno il tempo di esaminarlo ora, ma mi assicurerò di controllare le mie notifiche ogni tanto - e se qualcuno fa una buona risposta fattibile, allora accetterò.
Aske B.

Risposte:


1

Ecco una semplice implementazione di "Gruppo" che ti consente di navigare verso la radice e navigare nella struttura di quella radice come raccolta.

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;
      }
    }
  }
}

Quindi - dato un gruppo, puoi camminare sull'albero di quel gruppo:

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

La mia speranza nel pubblicare questo, è che mostrando come navigare su un albero (e dissipandone la complessità), potresti essere in grado di visualizzare le operazioni che vuoi eseguire sull'albero, e quindi rivedere i modelli da solo per vedere cosa si applica meglio.


0

Con la visione limitata che abbiamo dei requisiti di utilizzo o implementazione del tuo sistema è difficile diventare troppo specifici. Ad esempio, le cose che verrebbero prese in considerazione potrebbero essere:

  • il sistema è altamente concorrente (molti utenti)?
  • qual è il rapporto lettura / scrittura dell'accesso ai dati? (alta lettura, bassa scrittura è comune)

Per quanto riguarda gli schemi, ecc., Mi preoccuperei meno di quali schemi esatti emergano nella tua soluzione e di più sulla progettazione della soluzione effettiva. Penso che la conoscenza dei modelli di progettazione sia utile, ma non del tutto e per tutti: per usare un'analogia con lo scrittore, i modelli di progettazione sono più simili a un dizionario di frasi comunemente viste, piuttosto che a un dizionario di frasi che è necessario scrivere un intero libro a partire dal.

Il tuo diagramma mi sembra generalmente ok.

C'è un meccanismo che non hai menzionato e che consiste nell'avere una sorta di cache nella tua gerarchia. Ovviamente è necessario implementarlo con grande cura, ma potrebbe migliorare significativamente le prestazioni del sistema. Ecco una semplice interpretazione (avvertimento):

Per ciascun nodo nella gerarchia, archiviare i dati ereditati con il nodo. Fallo pigramente o attivamente, dipende da te. Quando viene effettuato un aggiornamento nella gerarchia, è possibile rigenerare i dati della cache per tutti i nodi interessati lì e quindi, oppure impostare flag "sporchi" nei punti appropriati e far rigenerare pigramente i dati interessati quando necessario.

Non ho idea di quanto sia appropriato nel tuo sistema, ma potrebbe valere la pena di considerarlo.

Inoltre, questa domanda su SO può essere rilevante:

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


0

So che questo è un po 'ovvio, ma lo dirò comunque, penso che dovresti dare un'occhiata a quanto Observer Pattern hai detto che hai un tipo di osservatore e quello che hai sembra un po' come il modello di osservatore per me.

paio di collegamenti:

DoFactory

oodesign

dai un'occhiata a quelli. altrimenti vorrei solo codificare ciò che hai nel tuo diagramma e quindi utilizzare il modello di progettazione per semplificare, se necessario. sai già cosa deve succedere e come dovrebbe funzionare il programma. Scrivi un po 'di codice e vedi se si adatta ancora.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.