2010-01-12 58 views
2

一位開發人員和我正在談論(輕描淡寫)對象的屬性的惰性加載。控制反轉,依賴注入瓦特/ SRP和延遲加載

  • 他說,要使用靜態IoC查找調用來解析對象的對象並延遲加載對象。
  • 我說違反SRP,並使用擁有的服務來解決該對象。

那麼,如何處理IoC和SRP之後的Lazy-Loading?

你不能單元測試那個懶加載的屬性。他斥責那個人說:「你已經爲UserStatsService進行了單元測試 - 這是你的代碼覆蓋範圍。」一個有效的點,但該屬性仍然未經測試,但「完整」的覆蓋。

設置/碼型:

  • 項目採用嚴格的依賴注入規則(在所有服務中,庫的構建函數注入,等等)。
  • 項目通過Castle的方式使用IoC(但可以是Unity等任何項目)。

一個例子如下。

public class User 
{ 
    public Guid UserId { get; set; } 

    private UserStats _userStats; 
    // lazy-loading of an object on an object 
    public UserStats UserStats 
    { 
    get 
    { 
     if (_userStats == null) 
     { 
     // ComponentsLookup is just a wrapper around IoC 
     // Castle/Unity/etc. 
     _userStats = 
      ComponentsLookup 
      .Fetch<UserStatsService>() 
       .GetByUserId(this.UserId); 
     } 
     return _userStats; 
    } 
    } 
} 

以上顯示了一個延遲加載對象的示例。我說不要使用它,並且在需要該對象的任何地方從UI層訪問UserStatsService。

編輯:下面的一個答案提醒我關於延遲加載的NHibernate技巧,這是虛擬化您的屬性,允許NHibernate創建延遲加載本身的過載。光滑,是的,但我們沒有使用NHibernate。

沒有人真正解決延遲加載的問題。一些好的文章,做題親近:

我看到延遲加載的好處。不要誤解我的意思,我只是懶惰地加載了我的複雜類型和它們的子類型,直到我轉向忍者的D.I.方式。好處是在用戶的統計信息顯示在用戶界面層,例如,在100行的列表中。但是對於DI,現在您必須引用幾行代碼才能獲得該用戶的統計信息(不違反SRP並且不違反德米特定律),並且必須經過這麼長的查找路徑100多次。

是的,加入緩存並確保UserStatsService被編碼爲Singleton模式,大大降低了性能成本。

但我想知道是否有其他人有[固執]的開發人員,不會屈服於IoC和D.I.完全規則,並具有有效的性能/編碼點來證明解決方法的正確性。

回答

4

實體本身不應該承擔延遲加載的責任。這是一項基礎設施問題,其解決方案將存在於別處。

假設實體在兩個不同的上下文中使用。在第一種情況下,它的孩子被大量使用並且急切地被裝載。在第二種情況下,它們很少被使用,並且被延遲加載。這也是該實體的擔憂嗎?配置會是什麼樣子?

NHibernate通過代理實體類型來回答這些問題。 IList<Entity>類型的屬性由基礎結構設置爲知道延遲加載的實現。該實體仍然幸福地不知道。父引用(如你的問題)也被處理,只需要一個簡單的屬性。

既然擔心是在實體之外,那麼基礎架構(ORM)負責確定上下文和配置(如預先加載/延遲加載)。

+0

+1我完全同意這個問題應該在實體之外。有了NHibernate(我知道它是如何重載延遲加載屬性的,是的),這很容易。但是,我們不使用NHibernate。另外,在你描述的罕見用例(沒有NHibernate)的情況下,這很容易使用大量的內存 - 將子屬性加載到回購級別。因此,延遲加載的概念僅適用於需要的情況下的高性能。我會繼續研究其他模式。 – eduncan911 2010-01-12 19:59:34

+0

在IList <>下執行延遲加載與NHibernate無關;這只是一個簡單的例子。它對靜態調用的主要好處是上下文敏感。當你將一個靜態調用放入一個類中時,你會自動將其上下文整個AppDomain,要求每個實例的工作方式完全相同。假設您有一個實體的列表頁面和導出。您可能會延遲加載列表頁面,但會導致出口負載過重(因爲您知道您將處理所有內容)。這種上下文行爲(以及批處理大小等)基本上被靜態調用所排除。 – 2010-01-13 00:24:19