4

我正在尋找避免構造函數注入過度使用的最佳做法。比如我有會議其中有幾個子實體實體像圖所示:構造函數注入過度使用

  • 會議
    1. MeetingContacts
    2. MeetingAttendees
    3. MeetingType
    4. 地址
    5. MeetingCompanies
    6. MeetingNotes

MeetingService類看起來象下面這樣:

public class MeetingService 
{ 
    private readonly IMeetingContactRepository _meetingContactRepository; 
    private readonly IMeetingAttendeeRepository _meetingAttendeeRepository; 
    private readonly IMeetingTypeRepository _meetingTypeRepository; 
    private readonly IAddressRepository _addressRepository; 
    private readonly IMeetingCompanyRepository _meetingCompanyRepository; 
    private readonly IMeetingNoteRepository _meetingNoteRepository; 
    private readonly IMeetingRepositoy _meetingReposity; 

    public MeetingService(IMeetingRepositoy meetingReposity, IMeetingContactRepository meetingContactRepository, IMeetingAttendeeRepository meetingAttendeeRepository, 
     IMeetingTypeRepository meetingTypeRepository, IAddressRepository addressRepository, 
     IMeetingCompanyRepository meetingCompanyRepository, IMeetingNoteRepository meetingNoteRepository) 
    { 
     _meetingReposity = meetingReposity; 
     _meetingContactRepository = meetingContactRepository; 
     _meetingAttendeeRepository = meetingAttendeeRepository; 
     _meetingTypeRepository = meetingTypeRepository; 
     _addressRepository = addressRepository; 
     _meetingCompanyRepository = meetingCompanyRepository; 
     _meetingNoteRepository = meetingNoteRepository; 
    } 

    public void SaveMeeting(Meeting meeting) 
    { 
     meetingReposity.Save(); 
     if(Condition1()) 
      _meetingContactRepository.Save(); 
     if(Condition2()) 
      _meetingAttendeeRepository.Save(); 
     if(Condition3()) 
      _meetingTypeRepository.Save(); 
     if(Condition4()) 
      _addressRepository.Save(); 
     if(Condition5()) 
      _meetingCompanyRepository.Save(); 
     if(Condition6()) 
      _meetingNoteRepository.Save(); 
    } 
    //... other methods 
} 

這裏有短短七年的依賴,但真正的代碼包含更多的人。我使用了"Dependency Injection Constructor Madness"中描述的不同技術,但我還沒有找到如何處理存儲庫依賴關係。

有什麼辦法可以減少依賴關係的數量並保持代碼的可測性?

+2

創建一個MeetingConfiguration類,其中構造函數爲您「放牧貓」。然後,您可以將MeetingConfiguration類傳遞給您正在初始化的任何內容。你不會解決多重過載的問題,但至少所有的重載都在一個地方。 – 2012-06-16 21:51:12

+7

如果你真的在這個'MeetingService'中寫信給所有的存儲庫,它肯定會做很多事情。把'MeetingService'分成只有共享密鑰的其他服務怎麼辦?我的意思是,你的工作單位是什麼?如果會議在'meetingReposity.Save();'後完成,然後發起一個事件並讓所有其他人訂閱。 –

+1

我認爲@ dtryon的建議要好得多。我不喜歡創建「配置」類的想法,只是爲了隱藏你實際上有很多依賴關係。這隻會讓代碼不那麼清晰,但沒有更好的組織。 –

回答

4

構造函數過度只是一個症狀 - 看起來你近似於unit of work有一個「主」類,它知道消息持久性的各種元素並將它們插入到整體保存中。

缺點是每個存儲庫通過暴露專用的Save方法來傳遞其他人的獨立性;但這是不正確的,因爲SaveMeeting明確指出存儲庫不是獨立的。

我建議識別或創建一個類型,存儲庫消耗;這集中了您的更改並允許您從一個地方保存它們。示例包括DataContext (LINQ to SQL)ISession (NHibernate)ObjectContext (Entity Framework)

您可以找到如何在信息庫中可能我的一個以前的答案工作的詳細信息:

Advantage of creating a generic repository vs. specific repository for each object?

一旦你的倉庫,你會指明他們將採取行動的背景。這通常映射到單個Web請求:在請求開始時創建一個通用工作單元實例,並將其交給所有存儲庫。在請求結束時,將更改保存在工作單元中,使存儲庫免費,以便擔心訪問哪些數據的

這整齊地捕捉和保存一切作爲一個單位。這與源代碼管理系統的工作副本非常相似:將系統的當前狀態拉入本地環境,使用它,並在完成後保存更改。您不會獨立保存每個文件 - 您將它們全部保存爲離散版本。

+0

感謝您的幫助。我發現你的答案非常有用。至於我的設計,它是這樣構建的,因爲我試圖從ActiverRecord移動到Repository。所以實施工作單位將是我的下一步。 – k0stya

0

您是否真的需要將存儲庫功能拆分爲多個接口?你需要分別嘲笑他們嗎?如果不是,則可以使用更少的接口和更多的方法。

但讓我們假設你的類真的需要那麼多的依賴。在這種情況下,你可以:

  • 創建一個配置對象(MeetingServiceBindings),提供所有的依賴關係。每個模塊可以有一個配置對象,而不僅僅是單個服務。我不認爲這個解決方案有什麼問題。
  • 使用依賴注入工具,如NInject。這很簡單,你可以在一個地方配置代碼的依賴關係,不需要任何瘋狂的XML文件。
+0

OP已*使用依賴注入。這些輔助類的問題是,你最終重複使用它們,正如你所建議的那樣!這聽起來不錯,除非你最終在沒有輔助類暗示的所有依賴的類中重用它們。這使得你的真正的依賴非常模糊。 –

+0

關於模糊依賴關係的好處。然後,您應該爲每個類創建一個配置對象,而不是整個模塊。請注意,「DI工具」與「DI」不同。 –

+1

另一個解決方案就是保持代碼原樣,如果類真的有很多依賴和構造函數注入是首選。 –

3

爲了擴大對我的上述評論一點點:

由於這個問題是針對如何管理存儲庫的依賴,我必須假設MeetingService是管理某種持久的承諾。在過去,當我看到類似MeetingService這樣的課程有很多依賴性時,顯然他們做得太多了。所以,你必須問自己,「我的交易邊界是什麼」。換句話說,您可以做出的最小承諾是什麼,這意味着會議已成功保存。

如果答案是在呼叫meetingReposity.Save();後成功保存會議,那麼這就是所有MeetingService應該管理的(用於提交)。

從本質上來說,其他一切都是保存會議這一事實的副作用(注意現在我們用過去式說話了)。此時,爲每個其他存儲庫訂閱事件更有意義。

這也具有將所有條件中的邏輯分離爲遵循SRP來處理該邏輯的訂戶類的良好效果。例如,當聯繫人存儲庫提交的邏輯經歷更改時,這變得很重要。

希望這會有所幫助。

1

前三個答案中的每一個都給出了處理抽象問題的重要建議和想法。但是,我可能會在上面的示例中看到太多內容,但這看起來像是一個聚合根過多的問題,而不是太多依賴本身。這與存儲庫注入基礎架構中的持久性機制缺乏或配置錯誤有關。

簡單地說,聯繫人,參加者,備註,& c。應該是會議本身的複合屬性(如果僅作爲單獨管理聯繫人的鏈接,則爲& c。objects/data);因此,您的持久性機制應該自動保存它們。

聽取布賴恩·沃茨的格言,‘構造的濫用只是一種症狀,’一對夫婦的其他可能性:

  • 你的持久性機制應處理自動會議圖形的持久性,並且無論是配置錯誤或缺少有能力做到這一點(布賴恩提出的所有這三點,我會加DbContext (EF 4.1+))。在這種情況下,應該只有一個依賴項 - IMeetingRepositoy - 它可以處理會議及其組合本身的原子保存。
  • SaveMeeting()是節約不只是鏈接到其他對象(聯繫人,與會者,&角),但也節省了這些對象,以及,在這種情況下,我會用dtryon是MeetingServiceSaveMeeting()正在做的遠遠超過了同意名字暗示,他的機制可以緩解它。