3

I built an Async task service executor that execute tasks by external request.

Each task contains the function void run(), so any programmer who want's to add a task to the system needs to inherit From BaseTask.

    interface ITask{
       void run();
    }
    abstract BaseTask : ITask{
       //force "run()" to set Result
       public ResultContainer Result {set; get;}
       void run();
    }

    class SomeTask : BaseTask {
       void run(){
           ////run the operation here, in the end, set the result.
           //force the programmer to set the Result;
           this.Result = new ResultContainer("task ok");
       }
    }

For internal reasons, the run() must be void.

Is there any way that I can force a programmer who wants to add a task to invoke Result in BaseTask and set its value? Do you think it is a bad practice?

Thanks

Jeremy McGee
  • 24,842
  • 10
  • 63
  • 95
fatnjazzy
  • 6,070
  • 12
  • 57
  • 83
  • You could add another method to ITask and BaseTask for onResult() with the implementation to set result but regardless relying on someone else to do what you want them to do is probably not reliable :) – Brian Colvin Oct 03 '11 at 19:17
  • This seems related: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface – Miserable Variable Oct 03 '11 at 19:52

2 Answers2

12

Yes, this is something to be avoided. Rules like this should be in place such that they're enforced by the compiler (rather than convention) when possible and practical.

In your case, you should do something like this:

public abstract class BaseTask
{
    public void Run()
    {
        Result = RunInternal();
    }

    public ResultContainer Result { get; set; }

    protected abstract ResultContainer RunInternal();
}

This will accomplish what you want semantically (that invoking the Run function externally will always cause the Result property to be set), and it forces the developer who inherits from BaseTask to supply the value that's being used. The only difference is that they will override (or, rather, implement) the RunInternal function instead of Run.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
1

I'm not sure if this fits some pre-imagined design pattern, but could you add another method to BaseTask that does have a return value,a nd have the developers implement that? For example (sorry if the code isn't 100% correct, not doing this in VS):

interface ITask{
   void run();
}

abstract BaseTask : ITask{
   //force "run()" to set Result
   public ResultContainer Result{set;get;}

   void run() {
       Result = runInternal();
   }

   protected abstract ResultContainer runInternal();

}

class SomeTask : BaseTask {
   protected override ResultContainer runInternal(){
       return new ResultContainer("task ok");
   }
}
CodingWithSpike
  • 42,906
  • 18
  • 101
  • 138
  • Its an old C++ idiom -- used to be called `public non-virtual function calling private pure virtual function`...or something similar. The overriding `function method` now needs to `protected`. See http://stackoverflow.com/questions/3970279/what-is-the-point-of-a-private-pure-virtual-function – Miserable Variable Oct 03 '11 at 19:36