7

我需要处理从服务返回的记录列表。
但是,记录的处理算法会根据记录上的某个字段完全改变。
为了实现这一点,我定义了一个只有一个方法的 IProcessor 接口:

public interface IProcessor
{         
    ICollection<OutputEntity> Process(ICollection<InputEntity>> entities);
}

IProcessor对于不同类型的处理,我有两个具体的实现。
问题是我需要同时使用所有实现IProcessor..所以我如何将它注入IProcessor到我的引擎类中来驱动整个事情:

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);
    }
}

这就是我目前正在做的事情..它看起来不太干净。
关于如何改进这个设计的任何想法......也许使用 IoC?

4

4 回答 4

5

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

public interface IProcessor
{         
    ICollection<OutputEntity> Process(InputEntity> entity);
    bool CanProcess (InputEntity entity);
}

那么你的代码不需要知道任何关于实现的信息:

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

    processor.Process(entity);
}

你的处理器会变魔术:

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

这种方法的好处是您可以从程序集等加载新处理器,而您的主要代码实现不必知道那里的任何单个实现。

于 2011-05-17T10:19:47.220 回答
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));
        }
    }
}

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

编辑

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

于 2011-05-17T10:17:07.977 回答
0

就个人而言,我可能会制作一个处理不同记录类型的 IProcessor 实现。就像是

public class ProcessorImpl : IProcessor
{
    // Either create them here or get them from some constructor injection or whatever.
    private readonly Type1Processor type1 = new Type1Processor(); 
    private readonly Type2Processor type2 = new Type2Processor(); 

    public ICollection<OutputEntity> Process(ICollection<InputEntity>> entities)
    {
        var type1Records = records.Where(x => x.SomeField== "Type1").ToList();
        var type2Records = records.Where(x => x.SomeField== "Type2").ToList();
        var result = new List<OutputEntity>();

        result.AddRange(type1.Process(type1Records));
        result.AddRange(type2.Process(type2Records));

        return result;
    }
}

然后,您可以将所有输入实体传递给 Process 方法,而不必担心它包含哪些记录类型。

这个实现缺乏一些可扩展性,所以如果需要它必须扩展(参见 Komet 的回答)。基本思想是让一个单独的服务负责选择流程实现。

于 2011-05-17T10:22:29.840 回答
0

这可能看起来有点复杂,但您可以使用属性来标记您的处理器,并在运行时读取属性并查看您拥有的处理器并从中构建字典:

public interface IProcessor
{         
    ICollection<OutputEntity> Process(ICollection<InputEntity>> entities);
}

[Processor("Type1")]
public class Processor1 : IProcessor
{
}

[Processor("Type2")]
public class Processor1 : IProcessor
{
}

public class Engine
{
  Dictionary<string, IProcessor> processors;

  public Engine()
  {
     // use reflection to check the types marked with ProcessorAttribute and that implement IProcessor
     // put them in the processors dictionary
     // RegisterService(type, processor);
  }

  public RegisterService(string type, IProcessor processor)
  {
    processor[type] = processor;
  }

  public void ProcessRecords(IService service)
  {  
     var records = service.GetRecords();  
     foreach(var kvp in processors)
     {
        kvp.Value.Process(records.Where(record => record.SomeField == kvp.Key));
     }
  }  
}
于 2011-05-17T10:27:32.170 回答