2

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

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可以同时创建AandB实例,并且我会 make Aand Bboth 声明对 的依赖ABFactory,但在这种情况下ABFactory无法访问两者的私有构造函数Aand B

假设语义是正确的(在这种情况下,A返回 an 的实例BB返回 another 的实例是合乎逻辑的A)那么解决这个问题的最佳方法是什么?

更新 1

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

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

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

4

2 回答 2

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) {}
于 2013-03-08T16:47:38.777 回答
0

First of all i would of course agree with what @PeterRitchie said in his comment as Cyclic Dependencies are a powerful design smell, secondly to break cyclic dependencies i go with an advise i read in Marc Seemann's book Dependency Inject in .NET and that is:

Attempt to address cycles by using events. If that fails, try an Observer. Only if you’re still unsuccessful should you consider breaking the cycle by using PROPERTY INJECTION.

If all of this fails, i would use the solution that Object Oriented Languages are famous for which is to introduce another dependency or abstraction to break the cycle which is what you actually did.

于 2013-03-09T23:56:42.643 回答