Time to refactor the IJob interface and JobDispatcher class
The JobDispatcher and the Jobs are a nice architecture because they follow two important principles of OO design, separation of concerns and inversion of control:
- The jobs only do their job.
- The jobs yield the responsability of decided where and when they should be executed to the dispatcher.
- The dispatcher only decide where and when the job should be executed.
To go even further with the inversion of control, we could rely on a container such as Unity to instanciate the different jobs, assigning them the different services they might require. Nevertheless, this is a feature that would be nice "by design", without assuming anything on the type of the container. The .Net framework allow us to do exactly that by using the IServiceProvider.
To achieve that, we just have to pass a IServiceProvider to the Execute method of the IJob interface:
public interface IJob
{
void Execute(IServiceProvider serviceProvider);
}
Now, the dispather has to provide the services to their jobs. So the JobDispatcher can-be a service provider. And, in order to allow the application to add services, it should use a ServiceContainer.
public abstract class JobDispatcher : IServiceProvider
{
IServiceProvider serviceContainer;
protected JobDispatcher() {
serviceContainer = new ServiceContainer();
}
protected JobDispatcher(IServiceProvider parentProvider) {
serviceContainer = new ServiceContainer(parentProvider);
}
#region IServiceProvider Membres
object IServiceProvider.GetService(Type serviceType) {
if ((serviceType == typeof(JobDispatcher))
|| (serviceType == typeof(IServiceProvider)))
return this;
else
return serviceContainer.GetService(serviceType);
}
#endregion
...
}
We have a new capability: we can register services specialized for the kind of JobDispatcher we are using! For instance, a JobDispatcher that executes all the jobs in a single thread will not need to synchronize its services, while JobDispatcher that uses several thread should.