2010-09-14 63 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