如何在运行时实现多个策略的使用

Sen*_*nin 7 c# strategy-pattern

我需要处理从服务返回的记录列表.
然而,记录的处理算法完全基于记录上的某个字段而改变.
为了实现这一点,我已经定义了一个只有一个方法的IProcessor接口:

public interface IProcessor
{         
    ICollection<OutputEntity> Process(ICollection<InputEntity>> entities);
}
Run Code Online (Sandbox Code Playgroud)

我有两种IProcessor不同类型处理的具体实现.
问题是我需要同时使用所有实现IProcessor..所以我如何注入IProcessor我的Engine类来驱动整个事情:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我目前正在做的事情......它看起来并不好看.
关于如何改进这种设计的任何想法......或许使用IoC?

Jan*_*oom 5

更改您的IProcessor界面,并添加一个新功能:

public interface IProcessor
{         
    ICollection<OutputEntity> Process(InputEntity> entity);
    bool CanProcess (InputEntity entity);
}
Run Code Online (Sandbox Code Playgroud)

那么您的代码不需要了解有关实现的任何信息:

foreach (var entity in entities) {
    var processor = allOfMyProcessors.First(p=>p.CanProcess(entity));

    processor.Process(entity);
}
Run Code Online (Sandbox Code Playgroud)

你的处理器会做出神奇的事:

public class Processor1 : IProcessor {
    public bool CanProcess(InputEntity entity) {
        return entity.Field == "field1";
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的好处是,您可以从程序集等加载新的处理器,而无需主代码实现必须知道任何单个实现.


koe*_*tsu 2

您可以将 SomeField 规范放入 IProcessor 实现中(您必须向 IProcessor 接口添加一个额外的字段),并根据您当前使用的处理器查找相应的记录。

一些代码可以解决这个问题:

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以在 ProcessRecords 方法中提供 IProcessors,或者将它们设置为 Engine 类中的 Properties(尽管我更喜欢构造函数注入)。

编辑

您可能还想研究其他答案中的 CanProcess 方法。尽管原理是相同的,但如果您需要更改标准来决定处理器是否应该处理类型,它提供了更具可扩展性/健壮性的解决方案。