4

你的工作是设计一个支持任务跟踪的 Project Plan 类库(类似于 MS Project 的工作方式)。这个类库有一个Task对象(等等)。

Task对象具有EstimatedHours( Double)、StartDate( DateTime) 和EndDate( DateTime) 属性等。一个Task对象可以有一个父对象Task和多个子Task对象。具有子代(是父代)的 a的EstimatedHoursStartDateEndDate属性Task取决于其直接子代的那些属性。parentTask是其孩子StartDate中最早的。StartDateparentTask是其孩子EndDate中最新的。EndDate父级是其子级的Task总和。因此,更改具有子项的这些属性是无效的。EstimatedHoursEstimatedHoursTask

您将如何处理在具有父级的任务上更改 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
4

6 回答 6

4

解决这个问题的正确方法是使用观察者设计模式。实现观察者模式的详细解释超出了本次讨论的范围。但是这里有一些很好的观察者模式链接。一个链接在这里,另一个在这里

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

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

于 2009-04-14T13:14:00.407 回答
2

我不确定这就是我实际的做法,但这里有一个不同的选择:不要让 Task 有孩子,而是使用两个对象,一个 Task 和一个实现 ITask 接口的 TaskSet。Task 会有自己的 StartDate、EndDate 和 EstimatedHours,但 TaskSet 会从其子任务中动态计算这些值。使用服务向 ITask 添加和删除子项。对于添加,它会在添加第一个孩子时将 Task 转换为 TaskSet。对于删除,它将在删除最后一个子项时将 TaskSet 转换回 Task,并根据最后一个子项的值设置属性。

于 2009-04-14T13:18:47.557 回答
1

我不认为这是模型责任的一部分,而是在它之上的控制器。

向模型添加事件或观察者模式会增加其他领域的复杂性,例如序列化,这是您想要避免的。

让它成为进行修改的类的责任,而不是模型本身。请记住:模型的职责是包含信息,而不是暗示业务规则。

于 2009-04-14T13:17:08.043 回答
1

请记住,当事件链中的一个事件引发异常时,将不会调用以下事件。因此,如果数据中注册了其他事件,则可能不会调用您的事件。

如果基本任务永远不会与其子任务脱节对您的应用程序至关重要,那么不要使用事件。

于 2009-04-14T13:17:59.133 回答
1

我将首先构建对象模型,以便它即时计算值。我将为您提供 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;
       }
    }
}

一旦你有了这个,你现在就拥有了运行系统所需的所有代码。您可能会发现系统性能足够好,然后就这样离开了。否则,您可以添加额外的功能来缓存结果,然后在对象更改时重置缓存。无论你做什么,一定要仔细分析它,因为你想确保你的缓存和过期不会比动态计算更昂贵。

于 2009-04-14T13:18:29.103 回答
0

我告诉我的 ASP.NET 开发人员,“事件监督。方法完成工作。”

事件应该只是调用方法的 IFblocks。没有尝试/捕获等。
方法完成所有数据访问/操作/验证/计算等。
这也在我的开发人员中创造了“可重用代码”的心态。

它使事情分开。
它也很好地平行于 MVC 概念。

控制器对事件做出反应。他们监督。他们调用模型方法。
模型做这项工作。

这不是一个完美的平行。
的确,它很简单,但它提供了很好的指导。

于 2009-04-14T13:32:08.070 回答