Comment pouvez-vous dire s'il faut utiliser un modèle composite ou une structure arborescente, ou une troisième implémentation?

14

J'ai deux types de clients, un type " Observateur " et un type " Objet ". Ils sont tous deux associés à une hiérarchie de groupes .

L'observateur recevra les données (calendaires) des groupes auxquels il est associé dans les différentes hiérarchies. Ces données sont calculées en combinant les données des groupes «parents» du groupe essayant de collecter des données (chaque groupe ne peut avoir qu'un seul parent ).

Le sujet pourra créer les données (que les observateurs recevront) dans les groupes auxquels ils sont associés. Lorsque des données sont créées dans un groupe, tous les «enfants» du groupe auront également les données, et ils pourront créer leur propre version d'une zone spécifique des données , mais toujours liées aux données d'origine créées (dans mon implémentation spécifique, les données d'origine contiendront la ou les périodes et le titre, tandis que les sous-groupes spécifient le reste des données pour les récepteurs directement liés à leurs groupes respectifs).

Cependant, lorsque le sujet crée des données, il doit vérifier si tous les observateurs concernés ont des données en conflit avec cela, ce qui signifie une énorme fonction récursive, pour autant que je puisse comprendre.

Je pense donc que cela peut se résumer au fait que je dois pouvoir avoir une hiérarchie dans laquelle vous pouvez monter et descendre , et certains endroits peuvent les traiter comme un tout (récursion, essentiellement).

De plus, je ne vise pas seulement une solution qui fonctionne. J'espère trouver une solution relativement facile à comprendre (au moins en termes d'architecture) et également suffisamment flexible pour pouvoir recevoir facilement des fonctionnalités supplémentaires à l'avenir.

Existe-t-il un modèle de conception ou une bonne pratique pour résoudre ce problème ou des problèmes de hiérarchie similaires?

MODIFIER :

Voici le design que j'ai: Diagramme de classe avec méthodes incluses.  La classe "Groupe" est la hiérarchie

La classe "Phoenix" est nommée ainsi parce que je n'ai pas encore trouvé de nom approprié.

Mais en plus de cela, je dois pouvoir cacher des activités spécifiques pour des observateurs spécifiques , même s'ils y sont attachés par le biais des groupes.


Un peu hors sujet :

Personnellement, je pense que je devrais être capable de couper ce problème en petits problèmes, mais cela m'échappe comment. Je pense que c'est parce qu'il implique plusieurs fonctionnalités récursives qui ne sont pas associées les unes aux autres et différents types de clients qui doivent obtenir des informations de différentes manières. Je ne peux pas vraiment envelopper ma tête. Si quelqu'un peut me guider sur la façon de mieux encapsuler les problèmes de hiérarchie, je serais très heureux de le recevoir également.

Aske B.
la source
Cela ressemble à un problème de théorie des graphes. Nous avons donc un digraphe représentant la hiérarchie des groupes. Chaque groupe est un sommet du graphique. Quelles propriétés sont vraies? Est-il vrai qu'il existe toujours un sommet unique navec un degré de 0 alors que chaque autre sommet a un degré d'au moins 1? Chaque sommet est-il connecté n? Le chemin vers l' nunique est-il unique? Si vous pouviez lister les propriétés de la structure de données et en résumer les opérations à une interface - une liste de méthodes - nous (I) pourrions peut-être trouver une implémentation de ladite structure de données.
Merci pour votre réponse. Il existe plusieurs hiérarchies de groupes qui ne sont pas attachés les uns aux autres, sauf via les observateurs, mais je ne pense pas qu'ils font partie des objets du graphique, ils ont juste un lien vers des sommets. Chaque groupe d'une hiérarchie ne peut avoir qu'un seul parent, mais 0 .. * enfants. Comment mettriez-vous cela en œuvre dans un graphique? Et seule une hiérarchie avec 1 groupe aura un degré de 0. Pour les hiérarchies à 2 groupes et plus, elles auront toutes un degré égal d'entrée et de sortie d'au moins 1. J'essaierai de lister ses méthodes pertinentes dans une heure, quand je suis au travail.
Les groupes fonctionnent-ils donc exactement comme le sous-classement en C #: vous pouvez sous-classer une classe de base, à l'exception qu'il existe une forêt (c'est-à-dire des arbres disjoints)? Eh bien, si vous connectez tous les pointeurs / références, alors vous avez déjà implicitement un graphique - vous n'avez rien d'autre à faire. La chose est, cependant, si vous voulez effectuer efficacement des opérations comme "Ces deux groupes sont-ils dans la même hiérarchie?" "Quel est l'ancêtre commun de ces deux groupes?" etc. vous avez besoin que le problème soit systématiquement analysé pour profiter de tout ce que vous savez à l'avance sur la structure.
Maintenant que j'ai vu votre diagramme, quelle est votre question exactement - s'il s'agit de l'approche de conception, je ne peux pas vraiment vous aider à ce stade car je suis moi-même nouveau dans les différentes méthodologies de conception. Cependant, si vous recherchez des O(n)algorithmes efficaces pour une structure de données bien définie, je peux y travailler. Je vois que vous n'avez pas appliqué de méthode de mutation Groupni de structure des hiérarchies. Dois-je supposer que ceux-ci seront statiques?
1
@Malachi Je n'ai pas trouvé de réponse. Malheureusement, je n'ai pas eu le temps de mener une enquête approfondie et j'ai dû passer à autre chose. Je n'ai pas non plus le temps de l'examiner maintenant, mais je m'assurerai de vérifier mes notifications de temps en temps - et si quelqu'un fait une bonne réponse viable, alors je l'accepterai.
Aske B.

Réponses:

1

Voici une implémentation simple de «groupe» qui vous permet de naviguer vers la racine et de naviguer dans l'arborescence de cette racine en tant que collection.

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

Donc - étant donné un groupe, vous pouvez parcourir l'arbre de ce groupe:

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

Mon espoir en publiant ceci, est qu'en montrant comment naviguer dans un arbre (et en dissipant la complexité de celui-ci), vous pourrez peut-être visualiser les opérations que vous souhaitez effectuer sur l'arbre, puis revisiter les modèles par vous-même pour voir ce qui s'applique le mieux.

Amy B
la source
0

Avec la vue limitée que nous avons des exigences d'utilisation ou d'implémentation de votre système, il est difficile d'être trop précis. Par exemple, les éléments qui pourraient être pris en considération pourraient être:

  • le système est-il très concurrent (beaucoup d'utilisateurs)?
  • quel est le rapport lecture / écriture de l'accès aux données? (lecture élevée, faible écriture est courante)

En ce qui concerne les modèles, etc., je m'inquiéterais moins des modèles exacts qui surgissent dans votre solution et plus de la conception de la solution réelle. Je pense que la connaissance des modèles de conception est utile, mais pas la finalité: pour utiliser une analogie d'écrivain, les modèles de conception ressemblent plus à un dictionnaire de phrases courantes, plutôt qu'à un dictionnaire de phrases, vous devez écrire un livre entier de.

Votre diagramme me semble généralement correct.

Il y a un mécanisme que vous n'avez pas mentionné et c'est d'avoir une sorte de cache dans votre hiérarchie. Évidemment, vous devez l'implémenter avec grand soin, mais cela pourrait améliorer considérablement les performances de votre système. Voici une prise simple à ce sujet (caveat emptor):

Pour chaque nœud de votre hiérarchie, stockez les données héritées avec le nœud. Faites cela paresseusement ou de manière proactive, c'est à vous de décider. Lorsqu'une mise à jour est effectuée dans la hiérarchie, vous pouvez soit régénérer les données de cache pour tous les nœuds affectés là-bas, soit définir des indicateurs `` sales '' aux endroits appropriés et faire en sorte que les données affectées soient par la suite recréées si nécessaire.

Je n'ai aucune idée de la pertinence de cela dans votre système, mais cela peut valoir la peine d'être considéré.

En outre, cette question sur SO peut être pertinente:

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

occulus
la source
0

Je sais que c'est un peu évident, mais je vais le dire de toute façon, je pense que vous devriez jeter un coup d'œil à Observer Pattern ce que vous avez mentionné que vous avez un type d'observateur et ce que vous avez ressemble un peu au modèle d'observateur pour moi.

quelques liens:

DoFactory

oodesign

vérifiez-les. sinon, je voudrais simplement coder ce que vous avez dans votre diagramme, puis utiliser le modèle de conception pour simplifier si nécessaire. vous savez déjà ce qui doit arriver et comment le programme est censé fonctionner. Écrivez du code et voyez s'il convient toujours.

Malachie
la source