你能删除内部类工厂的循环依赖吗?

时间:2013-03-08 16:01:45

标签: .net dependency-injection circular-dependency

假设我有两个类,但它们只能通过工厂创建,为了强制执行,我正在创建他们正在创建的对象的工厂内部类,以便他们可以访问私有构造函数。在这种情况下,一个类需要创建另一个类的实例,而第二个类需要创建第一个类的实例:

public class A
{
    public class Factory
    {
        private readonly B.Factory bFactory;

        public Factory(B.Factory bFactory)
        {
            this.bFactory = bFactory;
        }

        public A Build()
        {
            return new A(this.bFactory);
        }
    }
    private A(B.Factory bFactory)
    {
    }
}

public class B
{
    public class Factory
    {
        private readonly A.Factory aFactory;

        public Factory(A.Factory aFactory)
        {
            this.aFactory = aFactory;
        }

        public B Build()
        {
            return new B(this.aFactory);
        }
    }
    private B(A.Factory aFactory)
    {
    }
}

通常情况下,我会通过创建另一个名为ABFactory的工厂来解决此问题,该工厂可以同时创建AB个实例,并且我会AB声明对ABFactory的依赖,但在这种情况下,ABFactory无法访问AB的私有构造函数。

假设语义是正确的(在这种情况下,A返回B的实例和B的实例以返回另一个{{1}的实例是合乎逻辑的。那么解决这个问题的最佳方法是什么?

更新1

到目前为止,我的解决方案是创建一个名为A的新类。两个工厂中的每一个都声明对它的依赖而不是其他工厂。每个人都在自己的构造函数中使用该解析器注册自己(CircularDependencyResolver)。当他们去构建各自的对象时,他们会在解析器上调用this方法,该方法会查找其他已注册的工厂,或者抛出异常。

问题当然是我们推迟解决ResolveA的依赖关系,直到我们真正需要创建它,而不是在程序启动时,但它确实有效。 / p>

我仍然对其他解决方案感兴趣。

2 个答案:

答案 0 :(得分:1)

我的猜测:语义不可能正确。以哲学的方式,如果A只能在B的实例存在时创建(我在这里看不到工厂模式的相关性,在这种情况下与传统构造相比,因为你只是按代码方式移动问题,但不是语义明智的)B只能在A存在时创建,那么就没有办法,只要两者都不存在就可以创建两者中的任何一个。

必须有一个,可以在没有其他的情况下创建,除了A和B是同一个东西的一部分,这不是这里的情况(因为B应该创建一个自己的A实例)。你需要把另一个属性作为另一个属性。

在OOP中查看聚合组合中的概念之间的区别可能有助于直接获得语义,

顺便说一下,你是否在依赖注入上下文中查看它并不重要,因为你无法以任何方式创建实例。

可能,我错过了一些东西,但是......有趣的问题!

修改

好的,那么,那么:

public class A
{
    private int _privateInt;

    private B CreateB()
    {
        return B.Factory.Build();
    }

    public static class Factory
    {
        public static A Build()
        {
            return new A {_privateInt = 1};
        }
    }

    private A()
    {
    }
}

public class B
{
    public static class Factory
    {
        public static B Build()
        {
            return new B();
        }
    }

    private B()
    {
    }
}

但也许,我真的没有问题?

编辑2:

我无法想象你的情景,但为什么你需要将一个班级的工厂传递给另一个班级,特别是在DI的背景下?如果你想从另一个(A)获得一个类(比如说B)的新实例,为什么不让容器为你创建那个实例呢?

编辑3:

如果您的容器支持为您的实例解析Lazy初始值设定项,您可以将它们用作构造函数参数的类型:

public A(Lazy>B> b) {}

答案 1 :(得分:0)

首先,我当然同意@PeterRitchie在他的评论中所说的,因为Cyclic Dependencies是一种强大的设计气味,其次是打破循环依赖性,我在Marc Seemann的书Dependency Inject in .NET中读到了建议。那就是:

  

尝试使用事件来解决周期问题。如果失败了,试试吧   观察员。只有你仍然不成功,你才应该考虑   使用PROPERTY INJECTION打破周期。

如果所有这些都失败了,我将使用面向对象语言着名的解决方案,即引入另一个依赖或抽象来打破你实际所做的循环。