.NET对象层次结构 - 是否使用事件

4
你的工作是设计一个项目计划类库,支持任务跟踪(类似于 MS Project 的功能)。该类库有一个Task对象(以及其他对象)。
Task对象有一些属性,包括 EstimatedHours(Double)、StartDate(DateTime)和EndDate(DateTime)。Task对象可以有一个父Task,以及几个子Task。Task对象的EstimatedHours、StartDate和EndDate属性(当它是父Task时)取决于其直接子Task的这些属性。父Task的StartDate是其所有子Task的最早StartDate。父Task的EndDate是其所有子Task的最晚EndDate。父Task的EstimatedHours是其所有子Task的EstimatedHours之和。因此,在具有子Task的Task上更改这些属性是无效的。
当一个具有父Task的Task的EstimatedHours、StartDate或EndDate被更改时,你将如何处理呢? (父Task的属性反映了其子Task的属性,因此对子Task的任何更改可能需要相应地调整父Task的属性)
一种选择是为每个属性更改设置事件。父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

2
我不确定这是否是我实际操作的方式,但这里有一个不同的选项:不要允许任务具有子任务,而是使用两个对象,一个任务和一个任务集,它们都实现了ITask接口。任务将拥有自己的开始日期、结束日期和预计工时,但任务集将从其子任务动态计算这些值。使用服务将子任务添加到ITask中并将其删除。对于添加操作,当添加第一个子任务时,它会将一个任务转换为任务集。对于删除操作,当最后一个子任务被移除时,它会将任务集转换回任务,并从最后一个子任务上设置属性值。

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

一旦您完成了这些步骤,您现在拥有运行系统所需的所有代码。您可能会发现系统已经足够好用,就像这样保持不变。否则,您可以添加额外的功能来缓存结果,然后在对象更改时重置缓存。无论您做什么,请务必密切关注性能分析,以确保缓存和过期不比即时计算更昂贵。


1

我认为这不是模型的职责之一,而是控制器的职责。

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

将修改的责任归于进行修改的类,而不是模型本身。记住:模型的职责是包含信息,而不是暗示业务规则。


1
请注意,当事件链中的一个事件抛出异常时,后续事件将不会被调用。因此,如果数据注册了其他事件,可能会导致您的事件无法被调用。
如果对于您的应用程序来说,基本任务始终与其子任务保持联系至关重要,则不要使用事件。

0
我告诉我的ASP.NET开发者们:“事件来监控,方法来完成工作。”

事件应该只是IF代码块调用方法的简单操作。没有try/catch之类的东西。
方法负责所有数据访问/操作/验证/计算等等。
这使我的开发人员形成了“可重复使用代码”的思维模式。

这样可以将事物分离开来。
它也相当贴近MVC的概念。
控制器对事件做出反应。他们进行监视。他们调用Model方法。
Models(模型)才是真正的工作者。
这并不是完美的平行。
当然,这很简单,但它为良好的指导方针提供了依据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接