.NET 对象层次结构 - 到事件或不到事件
您的工作是设计一个支持任务跟踪的项目计划类库(类似于 MS Project 的工作方式)。 该类库有一个 Task
对象(等等)。
Task
对象具有 EstimatedHours
(Double
)、StartDate
(DateTime
)、和 EndDate
(DateTime
) 属性等。 一个 Task
对象可以有一个父 Task
对象和多个子 Task
对象。 具有子级(父级)的 Task
的 EstimatedHours
、StartDate
和 EndDate
属性取决于这些属性其直系子代的属性。 父 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
Your job is to design a Project Plan class library which supports the tracking of tasks (similar to how MS Project works). This class library has a Task
object (among others).
The Task
object has a EstimatedHours
(Double
), StartDate
(DateTime
), and EndDate
(DateTime
) properties, among others. A Task
object can have one parent Task
, and several children Task
objects. The EstimatedHours
, StartDate
, and EndDate
properties of a Task
which has children (is a parent) depend on those properties of its immediate children. The parent Task
's StartDate
is the earliest StartDate
of its children. The parent Task
's EndDate
is the latest EndDate
of its children. The parent Task
's EstimatedHours
is the sum of its children's EstimatedHours
. Therefore, it is invalid to change these properties on a Task
which has children.
How would you handle the use case where the EstimatedHours, StartDate, or EndDate are changed on a task which has a parent? (The parent's properties are a reflection of its children, so any changes to children may require the parent's properties to be adjusted to reflect the changes appropriately)
One option is to have an event for when each property changes. A parent Task
would listen for these events on its immediate children Task
objects, and make appropriate changes to its own properties when those events occurred. Is this a good approach, or is there a better way? How would you do it?
Here's a basic idea of what a Task
object might look like:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
解决这个问题的正确方法是使用观察者设计模式。 实现观察者模式的详细解释超出了本讨论的范围。 但这里有一些关于观察者模式的很棒的链接。 一个链接位于此处,另一个链接位于此处。
http://www.dofactory.com/Patterns/PatternObserver.aspx
http://en.wikipedia.org/wiki/Observer_pattern
The right approach to solve this problem will be to use Observer Design Pattern. Detailed explaination of implementing Observer pattern is beyond the scope of this discussion. But here are some great links for Observer Pattern. One link is here and another is here.
http://www.dofactory.com/Patterns/PatternObserver.aspx
http://en.wikipedia.org/wiki/Observer_pattern
我不确定这就是我实际执行的方法,但这里有一个不同的选项:不要允许任务有子任务,而是使用两个对象,即实现 ITask 接口的任务和任务集。 任务将有自己的 StartDate、EndDate 和 EstimatedHours,但 TaskSet 会根据其子任务动态计算这些值。 使用服务向 ITask 添加和删除子项。 对于添加,它会在添加第一个子项时将任务转换为任务集。 对于删除,当最后一个子项被删除时,它会将 TaskSet 转换回 Task,并根据最后一个子项的值设置属性。
I'm not sure this is how I'd actually do it, but here's a different option: Instead of allowing a Task to have children, use two objects, a Task and a TaskSet that implement an ITask interface. A Task would have its own StartDate, EndDate, and EstimatedHours, but a TaskSet would dynamically calculate those values from its child tasks. Use a service to add and remove children to an ITask. For adding, it would convert a Task into a TaskSet when the first child is added. For removing, it would convert the TaskSet back into a Task when then last child is removed and set the properties from the values on the last child.
请记住,当事件链中的一个事件引发异常时,将不会调用以下事件。 因此,如果有其他事件注册到数据,则您的事件可能不会被调用。
如果基本任务与其子任务永远保持联系对于您的应用程序至关重要,那么就不要使用事件。
Keep in mind that when one event in an event chain throws an exception, the following events are not going to be invoked. So if there are other events registered to the data it may be possible your event will not be called.
If it's crucial for your application that the base task is never out of touch with its children, then don't use events.
我将首先构建对象模型,以便它动态计算值。 我将为您提供 C#,因为我对它最熟悉(我还使用字段而不是属性来保持样本较小):
一旦您完成了此操作,您现在就拥有了运行系统所需的所有代码。 您可能会发现系统性能足够好,就这样吧。 否则,您可以添加附加功能来缓存结果,然后在对象更改时重置缓存。 无论你做什么,一定要仔细分析它,因为你想确保你的缓存和过期不会比即时计算更昂贵。
I would first build the object model so that it calculates on the fly the values. I am going to give you C# as I am most comftorble with it (I am also using fields instead of properties to keep the sample small):
Once you have this in place you now have all the code you need to run your system. You might find that the system performs well enough and leave it like this. Otherwise you can add in additional functionality to cache the result and then reset the cache when an object changes. Whatever you do be sure to profile it closely as you want to make sure your caching and expiration isn't more expensive then just calculating on the fly.
我不认为这是模型责任的一部分,而是控制器的责任。
向模型添加事件或观察者模式会增加其他领域的复杂性,例如序列化,这是您希望避免的。
使其成为进行修改的类的责任,而不是模型本身的责任。 请记住:模型的责任是包含信息,而不是暗示业务规则。
I would not consider this a part of the Model's responsibility, but rather of the Controller on top of it.
Adding events or observer patterns to a model adds complexity in other areas, such as serialization, which you will want to avoid.
Make it the responsibility of the class that makes the modification, not the model itself. Remember: the model's responsibility is to contain the information, not imply the business rules.
我告诉我的 ASP.NET 开发人员,“事件监督。方法完成工作。”
事件应该只不过是 IF 块调用方法而已。 没有尝试/捕获等
方法执行所有数据访问/操作/验证/计算等。
这也为我的开发人员创造了“可重用代码”的思维方式。
它使事物保持分离。
它也与 MVC 概念非常相似。
控制器对事件做出反应。 他们监督。 他们调用模型方法。
模型来做这项工作。
这不是完美的平行。
确实,它很简单,但它是非常好的指导方针。
I tell my ASP.NET developers, "Events supervise. Methods do the work."
Events should be little more than IFblocks calling methods. No try/catches etc.
Methods do all of the data access/manipulation/validation/calculation etc.
This creates "reusable-code" mindsets in my developers as well.
It keeps things separated.
It also parallels the MVC concepts pretty well.
Controllers react to events. They supervise. They call Model methods.
Models do the work.
It's not a perfect parallel.
True, it is simplistic, but it makes for pretty good guidelines.