據我所知,依賴注入將應用程序佈線邏輯與業務邏輯分開。另外,我試圖通過只注入直接的合作者來遵守德米特的法律。如何在依賴注入期間處理錯誤和異常
如果我正確理解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()
請注意,我在最後一個片段中剪掉了一些角。有關輸入範圍的更多信息,請參閱上述文章。
我可以看到在這種情況下連接池是如何適用的,但是當實際需要一個「連接」時會導致這種情況。例如,在應用程序運行時開始時加載和解析配置文件。 – ghostonline 2010-09-14 15:28:58
如果您必須將真正的工作作爲注射的一部分進行,那麼可以應用相同的規則 - 如果您無法完成注射,則應用無法啓動。因此,責任分工明確。因此有兩種選擇:不要啓動,或要求應用程序代碼對持續的故障具有恢復能力。我認爲,您所描述的那種純粹的初始化失敗應該導致無法啓動。 – djna 2010-09-14 15:57:18
什麼是最好的方式去做這件事?我的第一個解決方案處理所有其他業務邏輯之外的「例外」,但在我看來,混合佈線和業務邏輯。 – ghostonline 2010-09-15 07:21:57