.NET Object Hierarchy - к событию или не к событию - PullRequest
4 голосов
/ 14 апреля 2009

Ваша задача - разработать библиотеку классов Project Plan, которая поддерживает отслеживание задач (аналогично тому, как работает MS Project). Эта библиотека классов имеет объект Task (среди прочих).

Объект Task обладает, среди прочего, свойствами EstimatedHours (Double), StartDate (DateTime) и EndDate (DateTime). У объекта Task может быть один родительский Task и несколько дочерних Task объектов. Свойства EstimatedHours, StartDate и EndDate объекта Task, у которого есть дочерние элементы (являются родительскими), зависят от этих свойств его непосредственных дочерних элементов. Родитель Task StartDate является самым ранним StartDate из его детей. Родитель Task EndDate является последним EndDate его потомком. Родитель Task EstimatedHours - это сумма его детей EstimatedHours. Поэтому недопустимо изменять эти свойства для Task, у которого есть дочерние элементы.

Как бы вы справились со случаем использования, когда значения EstimatedHours, StartDate или EndDate изменяются в задаче, у которой есть родительский элемент? (Свойства родительского элемента являются отражением его дочерних элементов, поэтому любые изменения в дочерних элементах может потребоваться корректировка свойств родителя для надлежащего отражения изменений)

Один из вариантов - это событие, когда каждое свойство изменяется. Родитель Task будет прослушивать эти события на своих непосредственных дочерних объектах Task и вносить соответствующие изменения в свои собственные свойства при возникновении этих событий. Это хороший подход или есть лучший способ? Как бы ты сделал это?

Вот основная идея того, как может выглядеть Task объект:

Public Class Task

  Private mChildren As List(Of Task)

  Private mEndDate As DateTime = DateTime.MinVlue
  Public Property EndDate() As DateTime
    Get
      Return mEndDate 
    End Get
    Set(ByVal value As DateTime)
      mEndDate = value
      'What to do here?
    End Set
  End Property

  Private mEstimatedHours As Double = 0.0
  Public Property EstimatedHours() As Double 
    Get
      Return mEstimatedHours 
    End Get
    Set(ByVal value As Double)
      mEstimatedHours = value
      'What to do here?
    End Set
  End Property

  Private mStartDate As DateTime = DateTime.MinVlue
  Public Property StartDate() As DateTime
    Get
      Return mStartDate 
    End Get
    Set(ByVal value As DateTime)
      mStartDate = value
      'What to do here?
    End Set
  End Property

End Class

Ответы [ 6 ]

4 голосов
/ 14 апреля 2009

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

http://www.dofactory.com/Patterns/PatternObserver.aspx

http://en.wikipedia.org/wiki/Observer_pattern

Надеюсь, это поможет.

Ручит С.

2 голосов
/ 14 апреля 2009

Я не уверен, что именно так я и поступлю, но вот другой вариант: вместо того, чтобы разрешить Задаче иметь детей, используйте два объекта: Задачу и Набор задач, которые реализуют интерфейс ITask. Задача будет иметь свои собственные StartDate, EndDate и EstimatedHours, но TaskSet будет динамически вычислять эти значения из своих дочерних задач. Используйте сервис для добавления и удаления детей в ITask. Для добавления он преобразует задачу в набор задач при добавлении первого дочернего элемента. Для удаления он преобразует TaskSet обратно в Task, когда затем удаляется последний дочерний элемент, и устанавливает свойства из значений последнего дочернего элемента.

1 голос
/ 14 апреля 2009

Я бы сначала построил объектную модель, чтобы она на лету вычисляла значения. Я собираюсь дать вам C #, так как я наиболее удобен для него (я также использую поля вместо свойств, чтобы сохранить размер выборки):

public class Task
{

    public List<Task> Children=new List<Task>();
    public Task Parent;   
    private int _duration;

    public int Duration
    {

       get
       {
          if (Children.Count>0)
          { 
              return SumChildrenDuration();
          }

          return _duration;
       }

       set 
       {
          if (children.Count>0)
              throw new Exception("Can only add to leaves");
          _duration=value;
       }
    }
}

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

1 голос
/ 14 апреля 2009

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

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

1 голос
/ 14 апреля 2009

Я бы не считал это частью ответственности Модели, а скорее Контроллер поверх нее.

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

Возьмите на себя ответственность за класс, который вносит изменения, а не за саму модель. Помните: ответственность модели заключается в том, чтобы содержать информацию, а не подразумевать бизнес-правила.

0 голосов
/ 14 апреля 2009

Я говорю своим разработчикам ASP.NET: «События контролируются. Методы работают».

События должны быть немного больше, чем IFblocks, вызывающий методы. Не пытайтесь / ловит и т. Д.
Методы делают все данные доступа / манипуляции / проверки / расчета и т. Д.
Это также создает у моих разработчиков образ мышления с возможностью повторного использования.

Это держит вещи отдельно.
Он также очень хорошо соответствует концепции MVC.

Контроллеры реагируют на события. Они контролируют. Они вызывают методы Model.
Модели делают работу.

Это не идеальная параллель.
Правда, это упрощенно, но дает хорошие рекомендации.

...