临时对象中的依赖注入

时间:2019-07-15 23:27:25

标签: c# unit-testing design-patterns factory factory-pattern

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

我的大多数应用程序都是单例,并且很容易将单例作为彼此的依赖关系注入。

但是,我遇到一种情况,我会动态生成一些依赖于几个单例的瞬态对象。

以下是当前情况的一些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重构为一个普通的类,并制造一个类似工厂的东西:

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

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

2 个答案:

答案 0 :(得分:1)

我将定义一个工厂类,其唯一目的是构造您的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,获取包含可编译代码的小提琴。

答案 1 :(得分:0)

如果我错了,请纠正我,但我认为您的操作类似于“抽象工厂”模式。

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

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

基本思想是,您可以将“任务”分配给“调度程序”。

但是,要执行此操作,您需要使用另一个IoC容器(例如Autofac),因为默认的ASP.NET Core DI容器使此操作难以实现。