瞬态对象中的依赖注入

Dependency Injection in Transient Objects

我想要一些关于如何通过依赖注入构造某些对象的建议。

我的大部分应用程序都是单例,将单例作为彼此的依赖项注入非常简单。

但是,我遇到了动态生成一些依赖于多个单例的临时对象的情况。

这是当前情况的一些 C# 伪代码:

// random singletons
public static class SingletonA {...}
public static class SingletonB {...}
public static class SingletonC {...}

// random objects that all need to depend on some subset of the above singletons
public class BaseTask {...}
public class TaskA : BaseTask {...}
public class TaskB : BaseTask {...}
public class TaskC : BaseTask {...}

public class Scheduler {
    public Scheduler() {
    }

    public void Start() {
        // When these tasks are created is actually really dependent on business logic,
        // and each task executes a bunch of internal logic.
        // Each Task can create more children Task at arbitrary times too.
        ...
        var taskA = new TaskA();
        ...
        var taskB = new TaskB();
        ...
        var taskC = new TaskC();
        ...
}

在所有 TaskATaskBTaskC 中都有代码调用单例上的方法。另外,每个任务都可以构造新的任务。

如果我使用依赖注入,我可以这样做:

public class Scheduler {
    private ISingletonA _singletonA;
    private ISingletonB _singletonB;
    ...

    public Scheduler(ISingletonA singletonA, ISingletonB singletonB, ...) {
        _singletonA = singletonA;
        _singletonB = singletonB;
        ...
    }

    public void Start() {
        ...
        var taskA = new TaskA(_singletonA, _singletonB, ...);
        ...
        var taskB = new TaskB(_singletonA, _singletonB, ...);
        ...
        var taskC = new TaskC(_singletonA, _singletonB, ...);
        ...
    }
}

这看起来一团糟,所以我正在考虑将所有 TaskATaskBTaskC 重构为一个通用的 class 并制作类似工厂:

public class Scheduler {
    public TaskFactory _taskFactory

    public Scheduler(TaskFactory taskFactory) {
        _taskFactory = taskFactory;
    }

    public void Start() {
        ...
        var taskA = _taskFactory.NewTaskA(_taskFactory);
        ...
        var taskB = _taskFactory.NewTaskB(_taskFactory);
        ...
        var taskC = _taskFactory.NewTaskC(_taskFactory);
        ...
    }
}

有什么更好的主意吗?如果不是,我认为这不是工厂模式。有更准确的名字吗?

我会定义一个工厂 class,其唯一目的是构建您的 TaskX 对象,包括包含所有依赖项:

class MyTaskFactory : IMyTaskFactory
{
    private readonly ISingletonA _singletonA;
    private readonly ISingletonB _singletonB;

    public MyTaskFactory(ISingletonA singletonA, ISingletonB singletonB)
    {
        _singletonA = singletonA;
        _singletonB = singletonB;
    }

    public T Resolve<T>() where T : ITask
    {
        if (typeof(T) == typeof(TaskA)) return (T)(object)GetTaskA();
        if (typeof(T) == typeof(TaskB)) return (T)(object)GetTaskB();
        if (typeof(T) == typeof(TaskC)) return (T)(object)GetTaskC();

        throw new ArgumentException(string.Format("Type not supported: {0}", typeof(T).FullName));
    }

    protected TaskA GetTaskA()
    {
        return new TaskA(_singletonA);
    }

    protected TaskB GetTaskB()
    {
        return new TaskB(_singletonA, _singletonB);
    }

    protected TaskC GetTaskC()
    {
        return new TaskC(_singletonA, "Other runtime parameter");
    }
}

public class Scheduler
{
    protected readonly IMyTaskFactory _taskFactory;

    public Scheduler(IMyTaskFactory taskFactory)
    {
        _taskFactory = taskFactory;
    }

    public void Start()
    {
        var taskA = _taskFactory.Resolve<TaskA>();
        var taskB = _taskFactory.Resolve<TaskB>();
        var taskC = _taskFactory.Resolve<TaskC>();
    }
}

然后将工厂添加到组合根:

container.Register<IMyTaskFactory,MyTaskFactory>();

依赖项将显示在需要的地方。

单击 here 以获得包含可编译代码的 Fiddle。

如果我错了请纠正我,但我认为你所做的类似于抽象工厂模式。

我不确定您希望您的应用程序可配置到什么程度。我根据您当前的结构并根据您展示的内容建议创建一个应用程序文件,您可以在其中混合和匹配注入。

    {
        "Schedulers": [
            {
                "id": "A",
                "type": "....",
                "tasks": "tA, tB"
            },
            {
                "id": "B",
                "type": "....",
                "tasks": "tC"
            }
        ],
        "Tasks": [
            {
                "id": "tA",
                "type": "..."
            },
            {
                "id": "tB",
                "type": "..."
            },
            {
                "id": "tC",
                "type": "..."
            }
        ]
    }

基本思路是您可以将 "tasks" 分配给您的 "schedulers"。

但是,为了做到这一点,您需要使用另一个 IoC 容器,例如 Autofac,因为默认的 ASP.NET 核心 DI 容器使得这有点不可能实现。