2012-03-13 89 views
5

通常情況下,類的方法實例化,但沒有字段或屬性,有很多開銷?使用方法的類實例化有多快,但沒有字段或屬性?

我正在開發大量使用構造函數注入的ASP.NET MVC應用程序,並且一些控制器到目前爲止有多達10個依賴項。但由於大量的依賴關係,我使出了IMyAppServiceProvider接口和類,提供給所有依賴通用接入,通過DependencyResolver在MVC 3

我撕掉了我所有的應用程序特定代碼,並創建了一個Gist與我的基本設置(這不包括下面提到的BaseController設置)。

我還創建了一個BaseController類,它接受IMyAppServiceProvider。所有控制器都從這個基類繼承而來。基類採用IMyAppServiceProvider對象,併爲所有各種服務保護了變量。代碼看起來像這樣:

public class BaseController 
{ 
    protected IService1 _service1; 
    protected IService2 _service2; 
    protected IService3 _service3; 
    // ... 

    public BaseController(IMyAppServiceProvider serviceProvider) 
    { 
     _service1 = serviceProvider.GetService<IService1>; 
     _service2 = serviceProvider.GetService<IService2>; 
     _service3 = serviceProvider.GetService<IService3>; 
     // ... 
    } 
} 

這使得控制器的代碼「乾乾淨淨」。沒有私有/受保護的變量,構造函數中沒有賦值,服務被基類保護變量引用。 但是,每個請求都會實例化我的應用程序使用的每一項服務,無論特定控制器是否使用它們全部。

我的服務很簡單,只是包含一些業務邏輯和數據庫交互的方法調用。他們是無國籍的,沒有階級領域或屬性。因此,實例化應該很快,但我想知道這是否是最佳實踐(我知道這是一個加載的術語)。

+2

與往常一樣,輪廓第一。但是,我會猜測解決依賴性比實例化要慢數個數量級。 – 2012-03-13 20:22:12

+0

@insta哇,我沒有通過樹木看到森林。但是Ninject和/或其他IoC容器緩存依賴性解決? – 2012-03-13 20:23:54

+1

我在下面添加了一個答案,可以幫助你...我之前遇到過這個完全相同的問題。大多數人(包括我自己)不知道你可以重寫ASP.NET MVC用於創建控制器的控制器工廠。自定義的可以緊密集成您的IoC容器,並在需要時緩存依賴關係。 – 2012-03-13 20:33:02

回答

7

每個請求將實例,我 應用程序使用,具體的控制器是否使用所有的 他們每單服務。

我相信你自己回答了你的問題,這不是一個好方法。 此外,使用這種依賴解決方案(服務定位器注入)是一種不好的做法,因爲控制器的API變得混亂。控制器客戶端並不知道特定控制器真正需要哪些服務,所以最終可能會產生意外的運行時錯誤,單元測試也會很糟糕。

另外一個建議 - 將所有被認爲是基類的類都標記爲abstract關鍵字,這樣就可以避免將它用作具體類。設計和實現一個基類是一個具體的設計決策,所以明確你的設計意圖。

關於實例化的成本,你的情況不會有很大的不同,但總體上降低重物的成本實例,您可以:

+0

好的答案,但我想爲自己辯護一下。我的控制器API現在非常乾淨,因爲我將所有依賴關係抽象到服務定位器中。我可以爲每個控制器做一個更具體的接口,但是對於我的特定應用/負載,這是過度的。另外,我不會忍受運行時錯誤,因爲我的單元測試確保代碼運行並正確運行。但是我確實看到了你對缺乏依賴關係意識的觀點。現在我已經完成了這個工作,但我沒有簡單的方法來了解Controller的依賴關係(供我自己參考)。我現在好了。 – 2012-03-14 13:30:04

+0

好吧無論如何這是好的保持這樣的觀點 – sll 2012-03-14 13:40:45

2

我認爲你在這裏尋找的解決方案是使用自定義控制器工廠。這樣,每個創建的控制器都具有所需的相關性。這裏有一個StructureMap,從weblogs.asp.net

using StructureMap; 
public class StructureMapControllerFactory : DefaultControllerFactory { 

    protected override IController GetControllerInstance(Type controllerType) { 
     try { 
      return ObjectFactory.GetInstance(controllerType) as Controller; 
     } 
     catch (StructureMapException) { 
      System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave()); 
      throw; 
     } 
    } 
} 

protected void Application_Start() { 
    RegisterRoutes(RouteTable.Routes); 

    //Configure StructureMapConfiguration 
    // TODO: config structuremap   

    //Set current Controller factory as StructureMapControllerFactory 
    ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory()); 
} 
+0

感謝您的回覆,但我想我已經有這個?以前,我將控制器的構造函數設置爲接受其服務依賴關係的接口。 Ninject和它的Bootstrapper來完成這個任務。 – 2012-03-14 13:32:41

+0

那麼基礎控制器的每一個依賴關係又有什麼意義呢?如果您的控制器已被修剪,只需要他們需要的構造函數參數,但是它們被填充,那麼這是您可以做的最好的。 – 2012-03-14 14:14:03

+0

因此,我沒有在構造函數體中使用10個專用字段,10個構造函數參數和10個賦值,而是在BaseController中處理它。當我添加一個新的依賴項時,Controller構造函數不會改變。相反,BaseController會在它的構造函數中得到一個新的字段和賦值。同樣,這也簡化了我的測試設置。我有一個BaseTests類,它可以在一個地方爲每個模擬設置字段。 – 2012-03-14 14:36:50

相關問題