Extensible processing classes using reflection

I recently wanted to build an extensible set of processing classes. Each class can process certain objects it is provided.

I decided the simplest way to do this was to create an processor interface. The set of processing classes then is all classes that implement this interface. I use reflection to then find all the processors: that is, all implementations of the processor interface.

Assuming all processing is done on the object itself, the processor interface looks like this

public interface IProcessor
{
	bool CanProcess(ITarget target);

	void Process(ITarget target);
}

One of the processor implementations could look something like this

public class UpdateTotalProcessor : IProcessor
{
	public bool CanProcess(ITarget target)
	{
		return target.Items.Any();
	}

	public void Process(ITarget target)
	{
		target.Total = target.Items.Sum(item => item.Value);
	}
}

To utilise the processors, you’d end up with code similar to the following

private static readonly IEnumerable<IProcessor> Processors = InstancesOfMatchingTypes<IProcessor>();
		
private static IEnumerable<T> InstancesOfMatchingTypes<T>()
{
	Assembly assembly = Assembly.GetExecutingAssembly();
	return TypeInstantiator.Instance.InstancesOfMatchingTypes<T>(assembly);
}

public void Process(ITarget target)
{
	foreach(IProcessor processor in Processors.Where(p => p.CanProcess(target)))
		processor.Process(target);
}

Note that with this implementation, multiple processors can potentially match, and therefore process, a target. Also note that there is no ordering; adding ordering would be an easy extension.

With this scheme, adding new processors is dead easy. Simply add a new implementation of IProcessor to the assembly, and it will be automatically picked up and used.

Providing classes that derive one type from another is also simple using this scheme.

public interface IDeriver
{
	bool CanDerive(ITarget target);

	IDerived Derive(ITarget target);
}

public class SampleDeriver : IDeriver
{
	public bool CanDerive(ITarget target)
	{
		return true;
	}

	public IDerived Derive(ITarget target)
	{
		return new Derived(target);
	}
}

Obviously applying more than one deriver makes no sense in this context

private static readonly IEnumerable<IDeriver> Derivers = InstancesOfMatchingTypes<IDeriver>();
		
private static IEnumerable<T> InstancesOfMatchingTypes<T>()
{
	Assembly assembly = Assembly.GetExecutingAssembly();
	return TypeInstantiator.Instance.InstancesOfMatchingTypes<T>(assembly);
}

public IDerived Derive(ITarget target)
{
	IDeriver deriver = Derivers.FirstOrDefault(deriver => deriver.CanDerive(target));
	return deriver == null
		? null
		: deriver.Derive(target);
}

Once again ordering is undefined so if you have your derivers defined in such a way that more than one matches, you will end up with unpredictable results.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s