通过IOC容器使用Factory解析处理程序

本文关键字:处理 程序 Factory IOC 通过 | 更新日期: 2023-09-27 18:15:19

我的任务是重构一个整体MVC应用程序(一个控制器动作,超过1000行),使其更易于管理。

程序的目的是按特定顺序逐个解析不同类型的集合。

这是一个被提议的"更好"解决方案的例子…

public interface IFruit
{
}
public class Banana : IFruit
{
}
public class Apple : IFruit
{
}
public interface IFruitHandler<in TFruit> where TFruit : IFruit
{
    void Handle(IEnumerable<TFruit> fruit);
}
public class BananaHandler : IFruitHandler<Banana>
{
    public void Handle(IEnumerable<Banana> fruit)
    {
        Console.WriteLine("break apart the bunch of bananas");
        foreach (var banana in fruit)
        {
            Console.WriteLine("Peel the banana");
        }
    }
}
public class AppleHandler : IFruitHandler<Apple>
{
    public void Handle(IEnumerable<Apple> fruit)
    {
        foreach (var apple in fruit)
        {
            Console.WriteLine("Slice the apple");
        }
        Console.WriteLine("Throw the apple cores away");
    }
}

可以看到,每个水果都有自己的处理程序,每个处理程序的实现可能略有不同。有些处理程序在处理集合之前做一些事情,有些处理程序在处理集合之后做一些事情,有些处理程序在处理集合之前和之后做一些事情。

应用程序呈现一个对象(通过MVC控制器),将所有不同的水果集合作为属性(基本上是一个大视图模型)。我希望有某种中介可以接收所有这些集合并将它们传递给适当的处理程序。

这就是我想要的…

public class Mediator : IMediator
{
    private readonly Func<Type, IFruitHandler<IFruit>> handlerFactory;
    public Mediator(Func<Type, IFruitHandler<IFruit>> handlerFactory)
    {
        this.handlerFactory = handlerFactory;
    }
    public void Execute(IEnumerable<IEnumerable<IFruit>> fruitBundles)
    {
        foreach (var bundle in fruitBundles)
        {
            if (!bundle.Any())
                continue;
            var handler = handlerFactory(bundle.First().GetType());
            handler.Handle(bundle);
        }
    }
}

一个Fruit bundle将始终只包含一个水果,并且这些bundle将按照特定的顺序排列。调解员的签名。执行是足够宽松的一个包包含不同的水果。这是不应该发生的

问题是双重的....

我可以注册所有fruithandler与open泛型…

container.RegisterManyForOpenGeneric(typeof(IFruitHandler<>),typeof(IFruitHandler<>).Assembly);

但我有困难获得正确的工厂注册-我如何用简单的注入器注册工厂?

中介/处理程序工厂实现感觉很尴尬,就像IFruit接口一样(它实际上只是一个标记)——你会改变设计吗?

通过IOC容器使用Factory解析处理程序

您可以通过以下方式实现Mediator,但它有一些缺点:

  • 使用dynamic
  • Mediator需要引用Container(虽然这是ok的,如果你在你的组合根定义这个类)

我觉得这个问题太笼统了,无法提供任何具体的建议来更好地设计你的解决方案。

class Mediator : IMediator
{
    private readonly Container container;
    public Mediator(Container container)
    {
        this.container = container;
    }
    public void Handle(IEnumerable<IEnumerable<IFruit>> fruitBundles)
    {
        foreach (var bundle in fruitBundles)
        {
            if (bundle.Any())
            {
                dynamic instance = bundle.First();
                this.Handle(instance, bundle);
            }
        }
    }
    private void Handle<T>(T instance, IEnumerable<IFruit> bundle)
        where T : IFruit
    {
        var handler = this.container.GetInstance<IFruitHandler<T>>();
        handler.Handle(bundle.Cast<T>());
    }
}