Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

In my Domain I have an entity Activity which has a list of ITasks. Each implementation of this task has it's own properties beside the implementation of ITask itself. Now each operation of the Activity entity (e.g. Execute()) only needs to loop over this list and call an ITask method (e.g. ExecuteTask()).

Where I'm having trouble is when a specific tasks' properties needs to be updated, as in configuring the task (not as part of the execute method). How do I get an instance of that task? The options I see are:

  • Get the Activity by Id and cast the task I need. This'll either sprinkle my code with:
    • Tasks.OfType<SpecificTask>().Single(t => t.Id == taskId)
    • or Tasks.Single(t => t.Id == taskId) as SpecificTask
  • Make each task unique in the whole system (make each task an entity), and create a new repository for each ITask implementation

I don't like either option, the first because I don't like casting: I'm using NHibernate and I'm sure this'll come back and bite me when I start using Lazy Loading (NHibernate currently uses proxies to implement this). I don't like the second option because there are/will be dozens of different kind of tasks. Which would mean I'd have to create as many repositories.

Am I missing a third option here? Or are any of my objections to the two options not justified? How have you solved this problem in the past?

share|improve this question
    
First thing I would do is to implement few tests to see how Nhibernate behaves in first case. It might have some loopholes to get around it while using the cast variant. –  Euphoric Oct 23 '12 at 11:23
    
did you look at generic implementation if Repository and Unit of Work patterns ? –  Yusubov Oct 23 '12 at 11:40
    
@Euphoric Regardless of NHibernate, you're saying there's nothing wrong with casting itself in this case? –  dvdvorle Oct 23 '12 at 11:50
    
@ElYusubov No I didn't. That actually sounds like a pretty good idea. Hmm, this'll be something to look into. So the whole making a task an entity (where it previously wasn't) is no problem? Or better even, should the task have been an entity all along? Walks off mumbling... –  dvdvorle Oct 23 '12 at 11:57
    
No. Casting is wrong when it introduces coupling. But code dping the casting will be coupled with the type either way. –  Euphoric Oct 23 '12 at 12:02
add comment

2 Answers

up vote 2 down vote accepted

It is true that casting is bad when it introduces coupling. But that doesn't mean it's always bad. There's not a lot wrong with

ITask task = Tasks.Single(t => t.Id == taskId);
IArduousTask arduous = task as IArduousTask;

if (arduous != null)
{
    arduous.HaveLunchBreak();
}

task.DoTask();

This way, we're not tied to an implementation of ITask or IArduousTask. And any task can implement IArduousTask (with a different implementation of HaveLunchBreak(), if you choose) and HaveLunchBreak will automatically get called. But tasks that don't implement IArduousTask will not break.

However, in your case, you should probably also reconsider whether your Task objects should be mutable. It might be better to do this:

ITask updated = task.GetUpdated(someData);
activity.UpdateTask(updated);

Where GetUpdated is a new method on ITask and activity.UpdateTask matches on updated.ID and replaces the entire object in the array. This leaves the implementation of GetUpdated to the task type itself.

someData can either be all the data that could possibly be required to perform an update of any type of task, or it could be a dictionary (or dynamic object) containing data from a task-specific UI, passed into a specific task.

share|improve this answer
    
I like the way you think. –  dvdvorle Oct 23 '12 at 13:47
add comment

Activity should not know about the special property.

This knowledge belongs to a virtual method in the task class like this:

public class MyTask
{
    public virtual void ExecuteTask()
    {
        // ....
    }
}

public class MyTaskWithSpecialProperty : MyTask
{
    public int MySpecialProperty {get;set}
    public override void ExecuteTask()
    {
        CalculateSpecialProperty();
        base.ExecuteTask();
    }
    private void CalculateSpecialProperty()
    {
            MySpecialProperty++;
    }
}

Activity does not need to know about MySpecialProperty when executing

public class Activity 
{
    public void ExecuteTasks()
    {
        foreach(var task in this.Tasks)
            task.ExecuteTask();
    }
}
share|improve this answer
    
I meant updating as in having a task like SendMailTask, with a property TargetAddress. When a request comes in to change TargetAddress, how do I get an instance of that task of type SendMailTask (as opposed to a task of type ITask). Does this make sense? –  dvdvorle Oct 23 '12 at 12:55
    
I've updated the question to make this more clear. –  dvdvorle Oct 23 '12 at 12:58
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.