I need to process a list of records returned from a service.
However the processing algorithm for a record changes completely based on a certain field on the record.
To implement this , I have defined an IProcessor interface which has just one method :
public interface IProcessor
{
ICollection<OutputEntity> Process(ICollection<InputEntity>> entities);
}
And I have two concrete implementations of IProcessor
for the different types of processing.
The issue is that I need to use all implementations of IProcessor
at the same time .. so how do I inject the IProcessor
into my Engine class which drives the whole thing:
public class Engine
{
public void ProcessRecords(IService service)
{
var records = service.GetRecords();
var type1Records = records.Where(x => x.SomeField== "Type1").ToList();
var type2Records = records.Where(x => x.SomeField== "Type2").ToList();
IProcessor processor1 = new Type1Processor();
processor.Process(type1Records);
IProcessor processor2 = new Type2Processor();
processor.Process(type2Records);
}
}
This is what I'm doing at present .. and it doesn't look nice and clean.
Any ideas as to how I could improve this design .. using IoC perhaps ?
Change your IProcessor
interface, and add a new function:
public interface IProcessor
{
ICollection<OutputEntity> Process(InputEntity> entity);
bool CanProcess (InputEntity entity);
}
Then your code doesn't need to know anything about the implementation:
foreach (var entity in entities) {
var processor = allOfMyProcessors.First(p=>p.CanProcess(entity));
processor.Process(entity);
}
Your processor would do the magic:
public class Processor1 : IProcessor {
public bool CanProcess(InputEntity entity) {
return entity.Field == "field1";
}
}
Benefit of this approach is that you can load new processors from assemblies etc. without your main code implementation having to know about any single implementation out there.
You could put the SomeField specification in the IProcessor implementations (you'd have to add an extra field to the IProcessor interface), and find the corresponding records based on the processor you're using at the moment.
A bit of code to clear that up:
public interface IProcessor
{
ICollection<OutputEntity> Process(ICollection<InputEntity>> entities);
string SomeField{get;set;}
}
public class Engine
{
public Engine(IEnumerable<IProcessor> processors)
{
//asign the processors to local variable
}
public void ProcessRecords(IService service)
{
// getRecords code etc.
foreach(var processor in processors)
{
processor.Process(typeRecords.Where(typeRecord => typeRecord.SomeField == processor.SomeField));
}
}
}
Alternatively, you could provide the IProcessors in the ProcessRecords method, or set them as Properties in the Engine class ( though I prefer the constructor injection ).
Edit
You might also want to look into the CanProcess approach in the other answers. Though the principle is the same, it provides an even more extensible/robust solution if you need to change the criteria to decide if the processor should process the types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With