Please do NOT comment on bad practices used here. I am simply trying to tackle abstraction of this scenario with easy-to-describe examples.
I am trying to model a system that allows a user to enter an entity called TASK with certain configuration parameters and later have the TASK perform actions particular to that task.
Some examples of task definitions could be:
* Create a file {filename} in directory {path}.
* Copy file {filename} from {source directory} to {target directory}.
* Open {notepad application}, enter the text {sample text} and save the file as {filename}.
* Open {sample.docx}, type the text {sample text} at the end of the second paragraph.
Each task has a descriptive name and up to 5 parameters. In the examples above, parameters are enclosed in curly braces {}. Users would be instructed to carry on the above tasks and our application will verify if they have been completed. Each task must have the following function:
In a static world, I would create the following classes:
public abstract class TaskBase
{ public abstract void Perform(param1, ... param5); }
public class TaskFileCopy: TaskBase
{ public override void Perform(param1, ... param5) {} }
The problem is, tasks could be practically anything and after the program is compiled and deployed, more tasks need to be added. The first and worst thing that comes to mind is to keep on deriving from TaskBase, implement Perform, recompile and redeploy while keeping previous task results in tact.
Two problems here: By the time we hit 2,000 tasks, we will have at most 2,000 derived classes and secondly, the underlying OODB will be bogged down.
I was thinking of System.AddIn at one point but am convinced that this scenario has a better solution within OOP design.
I doubt that System.AddIn is suitable for this kind of thing. IMHO System.AddIn is for more static APIs and not for something that is going to be extended rapidly. Maybe you could have a look at MEF instead which is simpler and is based on extensibility and composition.
As you say, inheritance is also not the way to go because having 2000 derived classes will be a nightmare.
I think you should look for design patterns that are based on composition instead of inheritance. There are a few of them. One of them is the Composite pattern. With this pattern, you could have some very simple reusable tasks which you can combine into more complicated tasks. You can have tasks that include subtasks, that include subtasks and on and on.
Also you could look at the dynamic languages that can be hosted on the DLR. Like IronPython. You could create a script repository. Each script a task.
Also for inspiration you could have a look at Windows Workflow Foundation and specifically the Activities.
What is kind of obvious is that you need to maximize reuse. Of course this is easier said than done.
Best regards and good luck.