Как вы можете определить, использовать ли составной шаблон, древовидную структуру или третью реализацию?

14

У меня есть два типа клиентов, « наблюдатель „-типа и“ Тема » -типа. Они оба связаны с иерархией групп .

Обозреватель будет получать (календарь) данные из групп, с которыми он связан, в разных иерархиях. Эти данные рассчитываются путем объединения данных из «родительских» групп группы, пытающейся собрать данные (каждая группа может иметь только одного родителя ).

Субъект сможет создавать данные (которые получат наблюдатели) в группах, с которыми он связан. Когда данные создаются в группе, все «потомки» группы также будут иметь данные, и они смогут создавать свои собственные версии определенной области данных , но все же будут связаны с созданными исходными данными (в В моей конкретной реализации исходные данные будут содержать период (ы) времени и заголовок, в то время как подгруппы определяют остальную часть данных для получателей, непосредственно связанных с их соответствующими группами).

Однако, когда субъект создает данные, он должен проверить, есть ли у всех затронутых наблюдателей какие-либо данные, которые конфликтуют с этим, что, насколько я понимаю, означает огромную рекурсивную функцию.

Поэтому я думаю, что это может быть сведено к тому факту, что мне нужно иметь иерархию, в которой вы можете перемещаться вверх и вниз , и в некоторых местах можно рассматривать их как единое целое (рекурсия, в основном).

Кроме того, я не просто стремлюсь к решению, которое работает. Я надеюсь найти решение, которое будет относительно простым для понимания (по крайней мере, с точки зрения архитектуры), а также достаточно гибким, чтобы можно было легко получить дополнительные функции в будущем.

Существует ли шаблон проектирования или хорошая практика для решения этой проблемы или аналогичные проблемы иерархии?

РЕДАКТИРОВАТЬ :

Вот дизайн, который я имею: Диаграмма классов с включенными методами.  Класс «Группа» - это иерархия

Класс «Феникс» назван так, потому что я еще не придумал подходящего имени.

Но помимо этого мне нужно иметь возможность скрывать конкретные действия для конкретных наблюдателей , даже если они привязаны к ним через группы.


Немного не по теме :

Лично я чувствую, что должен быть в состоянии разбить эту проблему на более мелкие проблемы, но это ускользает от меня как. Я думаю, это потому, что он включает в себя несколько рекурсивных функций, которые не связаны друг с другом, и разные типы клиентов, которые должны получать информацию по-разному. Я не могу действительно обернуть голову вокруг этого. Если кто-нибудь может подсказать мне, как стать лучше в решении проблем иерархии, я был бы очень рад получить это.

Аске Б.
источник
Это звучит как проблема теории графов. Итак, у нас есть некоторый орграф, представляющий иерархию групп. Каждая группа - это вершина графа. Какие свойства сохраняются? Правда ли, что всегда существует уникальная вершина nс степенью 0, в то время как каждая другая вершина имеет степень не менее 1? Все ли вершины связаны с n? Является ли путь к nуникальному? Если бы вы могли перечислить свойства структуры данных и абстрагировать ее операции от интерфейса - списка методов - мы (I) могли бы предложить реализацию указанной структуры данных.
Благодарю за ваш ответ. Существует множество иерархий групп, которые не связаны друг с другом, кроме как через Наблюдатели, но я не думаю, что они являются частью объектов графа, они просто имеют ссылку на вершины в них. Каждая группа в иерархии может иметь только 1 родителя, но 0 .. * дочерних. Как бы вы реализовали это на графике? И только у иерархии с 1 входной группой будет степень в 0. Для 2-групповых иерархий и более они будут иметь одинаковую степень входа и выхода, равную по крайней мере 1. Я попробую перечислить соответствующие методы. через час, когда я на работе.
Так работают ли группы точно так же, как и создание подклассов в C #: вы можете создать подкласс одного базового класса, за исключением того, что существует лес (то есть непересекающиеся деревья)? Хорошо, если вы соединяете все указатели / ссылки, то неявно у вас уже есть график - вам больше ничего не нужно делать. Однако дело в том, что если вы хотите эффективно выполнять такие операции, как «Находятся ли эти две группы в одной иерархии?» "Каков общий предок для этих двух групп?" и т. д. вам нужно систематически анализировать проблему, чтобы воспользоваться всеми преимуществами, которые вы знаете о структуре.
Теперь, когда я увидел вашу диаграмму, в чем именно заключается ваш вопрос - если речь идет о подходе к дизайну, я не могу вам в этом помочь, поскольку сам я новичок в различных методологиях проектирования. Однако, если вы ищете эффективные O(n)алгоритмы для четко определенной структуры данных, я могу поработать над этим. Я вижу, вы не использовали никаких методов мутации Groupи структуры иерархий. Должен ли я считать, что они будут статичными?
1
@Malachi Я не нашел ответа. К сожалению, у меня не было времени полностью исследовать это и пришлось перейти к чему-то другому. Сейчас у меня нет времени и на это разбираться, но я буду проверять свои уведомления время от времени - и если кто-то даст хороший жизнеспособный ответ, я приму его.
Аске Б.

Ответы:

1

Вот простая реализация «Группы», которая позволяет вам перейти к корню и перемещаться по дереву этого корня как к коллекции.

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

Итак, если у вас есть группа, вы можете пройти по дереву этой группы:

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

Я надеюсь опубликовать это, показав, как перемещаться по дереву (и развеять его сложность), вы сможете визуализировать операции, которые вы хотите выполнить над деревом, а затем пересмотреть шаблоны самостоятельно, чтобы увидеть что лучше всего подходит.

Эми Б
источник
0

Из-за ограниченного представления о требованиях к использованию или реализации вашей системы трудно быть слишком конкретным. Например, вещи, которые будут приняты во внимание, могут быть:

  • Является ли система высококонкурентной (много пользователей)?
  • Каково соотношение чтения / записи доступа к данным? (высокий уровень чтения, низкий уровень записи обычно)

Что касается шаблонов и т. Д., Я бы меньше беспокоился о том, какие именно шаблоны возникают в вашем решении, а также о дизайне фактического решения. Я думаю, что знание шаблонов проектирования полезно, но не первостепенное и конечное: если использовать аналогию с писателем, шаблоны проектирования больше похожи на словарь часто встречающихся фраз, а не на словарь предложений, вы должны написать целую книгу из.

Ваша диаграмма выглядит нормально для меня.

Есть один механизм, который вы не упомянули, и который имеет некоторый кеш в вашей иерархии. Очевидно, что вы должны реализовать это с большой осторожностью, но это может значительно улучшить производительность вашей системы. Вот простой пример (предостережение emptor):

Для каждого узла в вашей иерархии сохраняйте унаследованные данные вместе с этим узлом. Делайте это лениво или проактивно, это ваше дело. Когда обновление выполнено в иерархии, вы можете либо заново сгенерировать данные кэша для всех затронутых узлов тут же, либо установить «грязные» флаги в соответствующих местах, и при необходимости ленивые данные будут заново генерироваться при необходимости.

Я понятия не имею, насколько это уместно в вашей системе, но, возможно, стоит подумать.

Также этот вопрос по SO может быть актуален:

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

occulus
источник
0

Я знаю, что это «Видимо очевидно», но я все равно собираюсь это сказать, я думаю, вам следует взглянуть на Observer Pattern упомянутое вами, что у вас есть Тип наблюдателя и то, что у вас выглядит для меня как образец Наблюдателя.

пара ссылок:

DoFactory

oodesign

проверить это. в противном случае я просто кодировал бы то, что вы имеете в своей диаграмме, а затем использовал бы шаблон проектирования для упрощения, если это необходимо. Вы уже знаете, что должно произойти и как программа должна работать. Напишите какой-нибудь код и посмотрите, подходит ли он еще.

Малахия
источник