2010-09-14 60 views
1

据我所知,依赖注入将应用程序布线逻辑与业务逻辑分开。另外,我试图通过只注入直接的合作者来遵守德米特的法律。如何在依赖注入期间处理错误和异常

如果我正确理解this article,正确的依赖注入意味着合作者在注入时应该完全初始化,除非需要延迟实例化。这意味着(并且在文章中实际提到)数据库连接和文件流等对象应该在注入时准备好并准备就绪。

但是,打开文件和连接可能会导致异常,应该在某个时候处理。什么是最好的方式去做这件事?

我能胜任在“时间线”之外,像下面的代码片段:

class Injector: 
    def inject_MainHelper(self, args): 
     return MainHelper(self.inject_Original(args)) 

    def inject_Original(self, args): 
     return open(args[1], 'rb') 

class MainHelper: 
    def __init__(self, original): 
     self.original = original 

    def run(self): 
     # Do stuff with the stream 

if __name__ == '__main__': 
    injector = Injector() 
    try: 
     helper = injector.inject_MainHelper(sys.argv) 
    except Exception: 
     print "FAILED!" 
    else: 
     helper.run() 

此解决方案,但是,开始与接线逻辑混合业务逻辑。

另一种解决方案是使用提供商:

class FileProvider: 
    def __init__(self, filename, load_func, mode): 
     self._load = load_func 
     self._filename = filename 
     self._mode = mode 

    def get(self): 
     return self._load(self._filename, self._mode) 

class Injector: 
    def inject_MainHelper(self, args): 
     return MainHelper(self.inject_Original(args)) 

    def inject_Original(self, args): 
     return FileProvider(args[1], open, 'rb') 

class MainHelper: 
    def __init__(self, provider): 
     self._provider = provider 

    def run(self): 
     try: 
      original = self._provider.get() 
     except Exception: 
      print "FAILED!" 
     finally: 
      # Do stuff with the stream 

if __name__ == '__main__': 
    injector = Injector() 
    helper = injector.inject_MainHelper(sys.argv) 
    helper.run() 

这里的缺点是供应商增加了复杂性和违反迪米特法则的。

当使用文章中讨论的依赖注入框架时,处理这种异常的最佳方法是什么?


SOLUTION的基础上,讨论与DJNA

首先,DJNA正确地指出,有生意和接线逻辑在我的第一个解决方案没有实际的混合。接线正在发生在它自己的,独立的类别中,与其他逻辑隔离。

其次,有范围的情况。而不是一个,有两个较小的示波器:

  • 该文件尚未验证的范围。在这里,注入引擎不能假定文件的状态,也不能建立依赖它的对象。
  • 成功打开并验证文件的范围。在这里,注入引擎可以基于提取的文件内容创建对象,而不用担心会造成文件错误。

进入第一个范围并获得足够的关于打开和验证文件的信息后,业务逻辑会尝试实际验证并打开文件(如djna所说的那样收获水果)。在这里,例外情况可以相应处理。当确定文件被正确加载和解析时,应用程序可以进入第二个作用域。

第三,与核心问题没有真正的关系,但仍然是一个问题:第一个解决方案在主循环中嵌入业务逻辑,而不是MainHelper。这使得测试更加困难。

class FileProvider: 
    def __init__(self, filename, load_func): 
     self._load = load_func 
     self._filename = filename 

    def load(self, mode): 
     return self._load(self._filename, mode) 

class Injector: 
    def inject_MainHelper(self, args): 
     return MainHelper(self.inject_Original(args)) 

    def inject_Original(self, args): 
     return FileProvider(args[1], open) 

    def inject_StreamEditor(self, stream): 
     return StreamEditor(stream) 

class MainHelper: 
    def __init__(self, provider): 
     self._provider = provider 

    def run(self): 
     # In first scope 
     try: 
      original = self._provider.load('rb') 
     except Exception: 
      print "FAILED!" 
      return 
     # Entering second scope 
     editor = Injector().inject_StreamEditor(original) 
     editor.do_work() 


if __name__ == '__main__': 
    injector = Injector() 
    helper = injector.inject_MainHelper(sys.argv) 
    helper.run() 

请注意,我在最后一个片段中剪掉了一些角。有关输入范围的更多信息,请参阅上述文章。

回答

0

我在Java EE,EJB 3和资源领域讨论过这个问题。

我的理解是我们需要区分引用到资源的注入和资源的实际使用。

以一个数据库连接的例子,我们有一些伪代码

InjectedConnectionPool icp; 

public void doWork(Stuff someData) throws Exception{ 

     Connection c = icp.getConnection(). 
     c.writeToDb(someData); 
     c.close(); // return to pool 


} 

据我了解:

1)。注入的资源不能是连接本身,而必须是连接池。我们抓住短时间的连接并返回它们。 2)。任何时候由于数据库或网络故障,任何Db连接都可能失效。所以连接池资源必须能够处理抛出不良连接并获得新连接。 3)。注射失败意味着组件不会启动。例如,如果注入实际上是JNDI查找,则可能发生这种情况。如果没有JNDI条目,我们无法找到连接池定义,无法创建池,因此无法启动组件。这与实际打开到DB的连接不一样... 4)。 ...在初始化时,我们实际上并不需要打开任何连接,如果没有这样做,只会给我们一个空的池 - 也就是说。完全一样的状态,如果我们已经跑了一段时间,数据库消失了,游泳池将/可能/应该扔掉过时的连接。

该模型似乎很好地定义了Demeter可能接受的一组职责。注入有助于准备地面,确保代码需要做某件事情时才能做到。代码有责任收获果实,尝试使用准备好的材料并应对实际的资源故障,并反对找不到资源。

+0

我可以看到在这种情况下连接池是如何适用的,但是当实际需要一个“连接”时会导致这种情况。例如,在应用程序运行时开始时加载和解析配置文件。 – ghostonline 2010-09-14 15:28:58

+0

如果您必须将真正的工作作为注射的一部分进行,那么可以应用相同的规则 - 如果您无法完成注射,则应用无法启动。因此,责任分工明确。因此有两种选择:不要启动,或要求应用程序代码对持续的故障具有恢复能力。我认为,您所描述的那种纯粹的初始化失败应该导致无法启动。 – djna 2010-09-14 15:57:18

+0

什么是最好的方式去做这件事?我的第一个解决方案处理所有其他业务逻辑之外的“例外”,但在我看来,混合布线和业务逻辑。 – ghostonline 2010-09-15 07:21:57