Search code examples
c#strategy-pattern

How to implement usage of multiple strategies at runtime


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 ?


Solution

  • 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.