¿Cómo puede saber si usar un patrón compuesto o una estructura de árbol, o una tercera implementación?

14

Tengo dos tipos de clientes, un tipo " Observador " y un tipo " Asunto ". Ambos están asociados con una jerarquía de grupos .

El observador recibirá datos (calendario) de los grupos con los que está asociado en las diferentes jerarquías. Estos datos se calculan combinando datos de los grupos 'principales' del grupo que intenta recopilar datos (cada grupo puede tener solo uno principal ).

El Sujeto podrá crear los datos (que recibirán los Observadores) en los grupos con los que están asociados. Cuando los datos se crean en un grupo, todos los 'hijos' del grupo también tendrán los datos, y podrán hacer su propia versión de un área específica de los datos , pero aún vinculados a los datos originales creados (en En mi implementación específica, los datos originales contendrán períodos de tiempo y títulos, mientras que los subgrupos especifican el resto de los datos para los receptores directamente vinculados a sus respectivos grupos).

Sin embargo, cuando el Sujeto crea datos, tiene que verificar si todos los Observadores afectados tienen datos que entren en conflicto con esto, lo que significa una gran función recursiva, por lo que puedo entender.

Así que creo que esto se puede resumir en el hecho de que necesito poder tener una jerarquía en la que pueda subir y bajar , y en algunos lugares poder tratarlos como un todo (básicamente, recursividad).

Además, no solo estoy apuntando a una solución que funcione. Espero encontrar una solución que sea relativamente fácil de entender (al menos en cuanto a arquitectura) y también lo suficientemente flexible como para poder recibir fácilmente funcionalidades adicionales en el futuro.

¿Existe un patrón de diseño, o una buena práctica para resolver este problema o problemas de jerarquía similares?

EDITAR :

Aquí está el diseño que tengo: Diagrama de clases con métodos incluidos.  La clase "Grupo" es la jerarquía

La clase "Phoenix" se llama así porque todavía no se me ocurrió un nombre apropiado.

Pero además de esto, necesito poder ocultar actividades específicas para observadores específicos , a pesar de que están unidos a ellos a través de los grupos.


Un poco fuera de tema :

Personalmente, siento que debería poder reducir este problema a problemas más pequeños, pero se me escapa cómo. Creo que es porque involucra múltiples funcionalidades recursivas que no están asociadas entre sí y diferentes tipos de clientes que necesitan obtener información de diferentes maneras. Realmente no puedo entenderlo. Si alguien puede guiarme en una dirección de cómo mejorar en encapsular problemas de jerarquía, me alegraría recibir eso también.

Aske B.
fuente
Esto suena como un problema de teoría de grafos. Entonces tenemos algunos dígrafos que representan la jerarquía de grupos. Cada grupo es un vértice en el gráfico. ¿Qué propiedades son ciertas? ¿Es cierto que siempre existe un vértice único ncon un grado de 0 mientras que cualquier otro vértice tiene un grado de al menos 1? ¿Está conectado cada vértice n? ¿Es el camino a núnico? Si pudiera enumerar las propiedades de la estructura de datos y resumir sus operaciones en una interfaz, una lista de métodos, nosotros (I) podríamos llegar a una implementación de dicha estructura de datos.
Gracias por su respuesta. Hay múltiples jerarquías de grupos que no están unidos entre sí, excepto a través de los Observadores, pero no creo que sean parte de los objetos del gráfico, solo tienen un enlace a vértices. Cada grupo en una jerarquía solo puede tener 1 padre, pero 0 .. * hijos. ¿Cómo implementaría eso en un gráfico? Y solo una jerarquía con 1 grupo tendrá un grado de entrada de 0. Para las jerarquías de 2 grupos y más grandes, todos tendrán un grado de entrada y salida igual de al menos 1. Intentaré enumerar sus métodos relevantes. en una hora, cuando estoy en el trabajo.
Entonces, ¿funcionan los grupos al igual que las subclases en C #: puede subclasificar una clase base, con la excepción de que hay un bosque (es decir, árboles disjuntos)? Bueno, si conecta todos los punteros / referencias, implícitamente ya tiene un gráfico, no necesita hacer nada más. Sin embargo, la cuestión es si desea realizar operaciones de manera eficiente como "¿Están estos dos grupos en la misma jerarquía?" "¿Cuál es el ancestro común de estos dos grupos?" etc. necesita analizar el problema sistemáticamente para aprovechar todas las cosas que sabe de antemano sobre la estructura.
Ahora que he visto su diagrama, ¿cuál es exactamente su pregunta? Si se trata del enfoque de diseño, realmente no puedo ayudarlo en este momento, ya que soy nuevo en las diversas metodologías de diseño. Sin embargo, si está buscando O(n)algoritmos eficientes para una estructura de datos bien definida, puedo trabajar en eso. Veo que no pusiste ningún método de mutación Groupy la estructura de las jerarquías. ¿Debo asumir que estos serán estáticos?
1
@Malachi No encontré una respuesta. Desafortunadamente no tuve tiempo para investigarlo completamente y tuve que pasar a otra cosa. Tampoco tengo tiempo para analizarlo ahora, pero me aseguraré de revisar mis notificaciones de vez en cuando, y si alguien hace una buena respuesta viable, entonces la aceptaré.
Aske B.

Respuestas:

1

Aquí hay una implementación simple de "Grupo" que le permite navegar a la raíz, y navegar el árbol de esa raíz como una colección.

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

Entonces, dado un grupo, puedes caminar por el árbol de ese Grupo:

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

Mi esperanza al publicar esto es que al mostrar cómo navegar por un árbol (y disipar la complejidad del mismo), puede visualizar las operaciones que desea realizar en el árbol y luego volver a visitar los patrones por su cuenta para ver Lo que mejor se aplica.

Amy B
fuente
0

Con la visión limitada que tenemos de los requisitos de uso o implementación de su sistema, es difícil ser demasiado específico. Por ejemplo, las cosas que serían consideradas podrían ser:

  • ¿Es el sistema altamente concurrente (muchos usuarios)?
  • ¿Cuál es la relación lectura / escritura de acceso a datos? (lectura alta, escritura baja es común)

En cuanto a los patrones, etc., me preocuparía menos qué patrones exactos surgen en su solución, y más sobre el diseño de la solución real. Creo que el conocimiento de los patrones de diseño es útil, pero no lo es todo: para usar una analogía de escritor, los patrones de diseño son más como un diccionario de frases comúnmente vistas, en lugar de un diccionario de oraciones, debe escribir un libro completo desde.

Su diagrama se ve generalmente bien para mí.

Hay un mecanismo que no ha mencionado y es tener algún tipo de caché en su jerarquía. Obviamente, debe implementar esto con mucho cuidado, pero podría mejorar significativamente el rendimiento de su sistema. Aquí hay una versión simple (advertencia de emptor):

Para cada nodo en su jerarquía, almacene datos heredados con el nodo. Haga esto de manera perezosa o proactiva, eso depende de usted. Cuando se realiza una actualización de la jerarquía, puede regenerar los datos de la memoria caché para todos los nodos afectados en ese momento, o establecer indicadores 'sucios' en los lugares apropiados, y hacer que los datos afectados se vuelvan a generar perezosamente cuando sea necesario.

No tengo idea de cuán apropiado es esto en su sistema, pero vale la pena considerarlo.

Además, esta pregunta sobre SO puede ser relevante:

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

oculto
fuente
0

Sé que esto es obvio, pero lo voy a decir de todos modos, creo que deberías echar un vistazo a lo Observer Pattern que mencionaste que tienes un tipo de observador y lo que tienes se parece al patrón de observador para mí.

par de enlaces:

DoFactory

oodesign

mira eso. de lo contrario, simplemente codificaría lo que tiene en su Diagrama y luego usaría el Patrón de diseño para simplificar si es necesario. usted ya sabe lo que debe suceder y cómo se supone que debe funcionar el programa. Escriba un código y vea si aún le queda.

Malaquías
fuente