I have one question regarding a model which is descried bellow:
A manager class holds tools and does something with them... Every tool does something...
Every tool should register itself (in a static method) to the manager (manager can contain static field of tools) so when a manger starts should be able to see all tools.
What is the best practice to do this ?
If I have to do this I would do it differently. I would have an interface for tool, something like ITool
which contains methods common to all tools like DoJob()
or whatever you feel appropriate.
Then I would design the manager class so accepts a list of ITool
via the constructor, and have a method that enables your to add more tools at design time.
interface ITool {
DoJob();
}
class Manager
{
public Manager(IEnumerable<ITool> tools);
public AddTool(ITool tool);
}
Edit: although I don't understand your requirements completely, but I think I have a feeling for what you are trying to do.
You said assume the ITool
s are private or have been loaded before the manager, I don't know why that might cause a problem for unless the classes that implement ITool
are private in an assembly different from the assembly the Manager
, if this is the case then please read on.
If your project is big or medium-to-big then I suggest to use MEF or Ninject DI container.
If you have a small or small-to-medium project then I wouldn't let the ITool
s or the Manager
register them self because this violates the Single Responsibility Principle.
Instead I would use an interface called IToolRepository
- kind of Repository design pattern -, let me show you:
ITool
is implemented:interface ITool {
DoJob();
}
class Hammer : ITool { // impl details }
interface IToolRepository {
IEnumerable<ITool> GetTools();
}
class ToolsRepository : IToolRepository {
IEnumerable<ITool> GetTools() {
// return ITool implementations from this assembly using
//any method you like, whether from database, web service, or reflection, etc ..
}
}
static RepositoryFactory {
IToolRepository CreateRepository() { // returns concrete repository };
}
Manager
exists:class Manager
{
public Manager(IToolRepository repository);
public Manager(IEnumerable<ITool> tools);
public AddTool(ITool tool);
}
Now when you want to create an instance of the Manager
you would call RepositoryFactory.CreateRepository()
method from the other assembly and inject the result into the Manager
like this:
new Manager(RepositoryFactory.CreateRepository());
This enhances testability, loose coupling and every class does what it is supposed to do, no more.