【问题标题】:.NET Object Hierarchy - To Event or not to Event.NET 对象层次结构 - 事件或不事件
【发布时间】:2010-10-19 08:20:28
【问题描述】:

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

Task 对象具有 EstimatedHours (Double)、StartDate (DateTime) 和 EndDate (DateTime) 等属性。一个Task 对象可以有一个父Task 和多个子Task 对象。有孩子(是父母)的TaskEstimatedHoursStartDateEndDate 属性取决于其直系孩子的这些属性。父TaskStartDate 是其子代中最早的StartDate。父级TaskEndDate 是其子级中最新的EndDate。父 TaskEstimatedHours 是其子 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

【问题讨论】:

    标签: .net oop class-hierarchy


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

            【解决方案5】:

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

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

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

            【讨论】:

              【解决方案6】:

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

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

              它使事物分开。
              它还与 MVC 概念非常相似。

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2016-03-29
                • 2021-12-11
                • 1970-01-01
                • 2023-04-07
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多