Hierarchy of .NET Objects - to an Event or Not to an Event

Your task is to create a Project Plan class library that supports task tracking (similar to how MS Project works). This class library has a Task object (among others).

The Task object has the properties EstimatedHours ( Double ), StartDate ( DateTime ), and EndDate ( DateTime ). A Task object can have one parent Task element and several child Task objects. The properties of EstimatedHours , StartDate and EndDate a Task , which have children (parent), depend on the properties of its immediate children. Parent Task StartDate is the earliest StartDate its children. Parent Task EndDate is the last EndDate its children. The parent of the Task EstimatedHours is the sum of its children of EstimatedHours . Therefore, it is not valid to change these properties to a Task that has children.

How would you handle the use case when the values ​​of EstimatedHours, StartDate, or EndDate were changed to a job with a parent? (parent properties are a reflection of its children, so any changes to children may require that the parent properties be adjusted to reflect the corresponding changes)

One option is to have an event when each property changes. The parent Task will listen for these events on its child Task objects and make appropriate changes to its own properties when these events occur. Is this a good approach, or is there a better way? How would you do that?

Here is the basic idea of ​​what the 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 
+4
source share
6 answers

The correct approach to solving this problem will be to use the Observer design pattern. A detailed explanation of the implementation of the Observer scheme is beyond the scope of this discussion. But here are some great links for Pattern Observer. One link is here and the other is here .

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

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

Hope this helps.

Ruchit S.

+4
source

I'm not sure that this is the way I did it, but here is another option: instead of the task of having children, use two objects - Task and TaskSet, which implement the ITask interface. The task will have its own values ​​StartDate, EndDate and EstimatedHours, but the TaskSet will dynamically calculate these values ​​from its child tasks. Use the service to add and remove children in ITask. To add, it converts the task to a TaskSet when adding the first child. For deletion, it converts the TaskSet back to the task when the latter is deleted and sets properties from the values ​​for the last child.

+2
source

I would not consider this part of the responsibility of the Model, but rather the Controller over it.

Adding events or observer patterns to the model adds complexity in other areas, such as serialization, that you want to avoid.

To take responsibility is the class that produces the modification, not the model itself. Remember: the responsibility of the model is to contain information, not imply business rules.

+1
source

Keep in mind that when one event in the event chain throws an exception, the following events will not be raised. Therefore, if there are other events recorded in the data, your event may not be triggered.

If it is important for your application that the basic task never touches your children, do not use events.

+1
source

First, I would build an object model so that it counts values ​​on the fly. I am going to give you C # since I am very compatible with it (I also use fields instead of properties to keep the sample small):

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

Once you have this place, now you have all the code you need to start your system. You may find that the system works well enough and leaves it that way. Otherwise, you can add additional functions to cache the result, and then reset the cache when the object changes. No matter what you do, be sure to consult it carefully, as you want your caching and endurance not to be more expensive, but just calculated on the fly.

+1
source

I will tell my ASP.NET developers: "Event control. Methods do the job."

Events should be slightly larger than IFblocks invocation methods. No attempts / catches, etc.
Methods do all data access / manipulation / validation / calculation, etc.
It also creates a "thinking for reuse" in my developers.

This keeps things separate.
It also goes well with MVC concepts.

Controllers respond to events. They control. They call model methods.
Models do their job.

This is not a perfect parallel.
True, this is simplistic, but it makes pretty good recommendations.

0
source

All Articles