Come si può sapere se usare 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'Observer riceverà (calendario) dati dai gruppi a cui è associato attraverso le diverse gerarchie. Questi dati vengono calcolati da combinando i dati dei gruppi "padre" del gruppo che tenta di raccogliere dati (ciascun gruppo può avere solo un genitore ).

L'Oggetto 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, tutti i "figli" del gruppo avranno anche i dati, e saranno in grado di fare la propria versione di un'area specifica dei dati , ma comunque collegati ai dati originali creati (nella mia specifica implementazione, i dati originali conterranno periodo / i di tempo e titolo, mentre i sottogruppi specificheranno il resto dei dati per i ricevitori direttamente collegati ai rispettivi gruppi).

Tuttavia, quando l'Oggetto crea dati, deve verificare se tutti gli Observer interessati hanno dei dati che confliggono con questo, il che significa un'enorme funzione ricorsiva, per quanto posso capire.

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

Inoltre, non sto solo puntando a una soluzione che funzioni. Spero di trovare una soluzione che sia relativamente facile da comprendere (almeno per quanto riguarda l'architettura) e abbastanza flessibile da poter ricevere facilmente ulteriori funzionalità 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: Schema di classe con metodi inclusi. La classe

La classe "Phoenix" è chiamata così perché non ho ancora pensato ad un nome appropriato.

Ma oltre a questo ho bisogno di poter nascondere attività specifiche per osservatori specifici , anche se sono collegati a loro attraverso i gruppi.

Un po 'fuori tema :

Personalmente, penso che dovrei riuscire a ridurre questo problema a problemi più piccoli, ma mi sfugge come. Penso che sia perché coinvolge più funzionalità ricorsive che non sono associate tra loro e tipi di client diversi che hanno bisogno di ottenere informazioni in modi diversi. Non riesco davvero a capirlo. Se qualcuno mi può guidare in una direzione su come migliorare l'incapsulamento dei problemi di gerarchia, sarei molto lieto di ricevere anche questo.

    
posta Aske B. 15.08.2012 - 17:53
fonte

3 risposte

1

Ecco una semplice implementazione di "Gruppo" che ti permette di navigare verso il Root e navigare nell'albero di Root come collezione.

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 su quell'albero del gruppo:

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

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

    
risposta data 17.08.2012 - 19:34
fonte
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 potrebbero venire in considerazione potrebbero essere:

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

Per quanto riguarda i pattern, ecc., mi preoccuperei meno di quali siano i pattern esatti nella tua soluzione e di più sulla progettazione della soluzione reale. Penso che la conoscenza dei modelli di progettazione sia utile, ma non l'essere tutto e il tutto alla fine: per usare un'analogia con lo scrittore, gli schemi di progettazione sono più come un dizionario di frasi comunemente viste, piuttosto che un dizionario di frasi che devi scrivere un intero libro da.

Il tuo diagramma sembra generalmente ok per me.

C'è un meccanismo che non hai menzionato e che ha una sorta di cache nella tua gerarchia. Ovviamente è necessario implementarlo con molta attenzione, ma potrebbe migliorare significativamente le prestazioni del sistema. Ecco una semplice descrizione (caveat emptor):

Per ciascun nodo della gerarchia, memorizzare i dati ereditati con il nodo. Fatelo pigramente o pro-attivamente, dipende da voi. Quando viene effettuato un aggiornamento della gerarchia, è possibile rigenerare i dati della cache per tutti i nodi interessati, quindi o impostare i flag "dirty" nelle posizioni appropriate e rigenerare pigramente i dati interessati quando necessario.

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

Inoltre, questa domanda su S.O. potrebbe essere rilevante:

link

    
risposta data 31.08.2012 - 15:54
fonte
0

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

paio di link:

DoFactory

oodesign

controlla quelli fuori.  altrimenti mi limiterò a codificare ciò che si ha nel diagramma e quindi utilizzare il modello di progettazione per semplificare se necessario. sai già cosa deve accadere e come dovrebbe funzionare il programma. Scrivi un codice e vedi se è ancora adatto.

    
risposta data 04.10.2012 - 17:16
fonte

Leggi altre domande sui tag