2013-03-25 80 views
1

考虑下面的类层次结构在复杂层次注射运行时依赖抽象工厂

  • ClassA的需要ClassB的
  • ClassB的需要ClassC

我们得到了一个依赖关系图如下:

ClassA --> ClassB --> ClassC 

所以如果我们使用DI,我们将ClassC和ClassB注入到ClassA中。

但是现在让我们假设ClassC是一个运行时依赖项(例如某种策略)。建议的方式注入运行时的依赖是引入一个抽象工厂就像一个

ClassCFactory 

现在我们可以注入ClassCFactory到ClassB的,并得到如下图

ClassA --> ClassB --> ClassCFactory 

现在我们有一个方法ClassB的其中我们可以打电话让工厂做好工作。例如

ObjB.SelectC(MyRuntimeValue) 

但是现在在我们的应用中,我们不知道什么ClassB的(或许还有一些涉及更多层)。一种解决方案可能是有SelectC在ClassA的

ObjA.SelectC(MyRuntimeValue) -(calls)-> ObjB.SelectC(MyRuntimeValue) 

,或者我们干脆违反法律德米特和做类似

ObjA.ObjB.SelectC(MyRuntimeValue) 

我认为每个人都同意,第二个解决方案是不是要走的路。但第一个解决方案也有一些缺点,特别是如果我们之间有更多的层。

我们也可以拉出工厂的一个层次来创建ClassB,但是ClassB真的是运行时的依赖关系吗? 你建议什么解决方案?或者它甚至是一个糟糕的课程设计?

恕我直言,总是更好地依赖于对象实际需要做的工作,而不是创建所需对象的工厂。但有了这个想法一记DI容器将是无用的...

回答

2

建议的方式注入运行时的依赖是引入一个 抽象工厂

你不一定需要一个抽象工厂在运行时注入事物。您可以使用setter注入或方法注入将简单的依赖关系直接传递给对象。

当您必须生成一系列相关对象的对象时,抽象工厂才是选项系列但直到运行时间才知道哪个系列。你的例子中没有显示这种情况,所以YAGNI/KISS将表示不使用它。

但是现在在我们的应用程序中,我们不知道任何关于ClassB (也许涉及到更多的图层)。

您能否提供一些在您的情况下为什么会出现这种情况的详细信息?对我来说,似乎总会有某种类型的执行上下文知道ClassB并能够向其中注入C。不过,它不需要与将ClassB注入到A中的执行上下文相同。

IoC也被称为好莱坞原则 - "Don't call us, we'll call you""we"是谁以及"call you"部分发生的时间取决于您的应用程序可能会有很大差异,但没有硬性规定。如果您担心ObjectA可能对ClassC过于了解,只需将其注入委托给其他人。 DI容器可以帮助很多。

+0

好的,我会给你更具体的含义:ClassC是一个抽象类Encrytption,它对不同类型的加密有不同的实现。 ClassB是一个装饰器,用Encryption装饰FileStream。而ClassA是某种可序列化的对象,需要序列化一个流。 – 2013-03-26 10:43:17

+0

什么决定使用哪种类型的加密?您可以让ClassA的消费者决定并将3个俄罗斯娃娃放在一起(加密,FileStreeamDecorator和ClassA),或者一些外部对象可以选择一个加密,将其放入FileStreamDecorator并将其全部传递给ClassA的消费者......真的取决于您的上下文。 – guillaume31 2013-03-26 11:28:52

+0

选择正确的加密取决于我们加载或我们保存。加载时,我们询问标题,使用哪种加密,然后我们询问用户密码并开始阅读和解密。在保存时,我们必须使用与加载时相同的加密。有一种特殊的导出方式,用户最终可以决定使用哪种加密方式。 – 2013-03-26 11:54:56

0

我发现运行时依赖也很麻烦,我认为抽象工厂的框架开销是烦人的额外的代码,我不希望存在。但是,我还没有想到一个更好的方式来做这件事。

但是在上面的示例中,我的两个选择之间似乎没有任何显着差异。

在一种情况下,你有

ObjA.ObjB.SelectC(MyRuntimeValue) 

,并在其他你会

ObjA.ObjB.ObjC 

这些选项都具有相同的优点和缺点我的脑海里。正如你注意到的,为了避免违反得墨忒耳定律,你必须添加许多通过函数。这并不总是值得的,但绝对值得考虑。