2012-03-13 5 views
5

Generalnie tworzenie klas metodami, ale bez pól i właściwości, ma dużo narzutów?Jak szybkie jest tworzenie instancji klas za pomocą metod, ale bez pól i właściwości?

Pracuję nad aplikacją ASP.NET MVC, która intensywnie korzysta z wtrysku konstruktora, a niektóre sterowniki mają do 10 zależności. Ale ze względu na dużą liczbę zależności, że ucieka się do IMyAppServiceProvider interfejs i klasy udostępniającej rodzajowy dostęp do wszystkich zależności, przez DependencyResolver w MVC 3.

ja wyrwane całe specyficzny kod aplikacji i stworzył z Gist moja podstawowa konfiguracja (nie dotyczy to jednak poniższej konfiguracji BaseController).

Utworzyłem również klasę BaseController, która akceptuje IMyAppServiceProvider. Wszystkie kontrolery dziedziczą z tej klasy bazowej. Klasa podstawowa pobiera obiekt IMyAppServiceProvider i ma zmienne chronione dla wszystkich różnych usług. Kod wygląda mniej więcej tak:

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>; 
     // ... 
    } 
} 

To sprawia, że ​​kod dla kontrolerów jest "skrzypiący w czystości". Brak zmiennych prywatnych/chronionych, żadnych przydziałów w konstruktorze i usług odwołują się do zmiennych chronionych klasy podstawowej. Jednak każde żądanie będzie tworzyło każdą usługę, z której korzysta moja aplikacja, niezależnie od tego, czy dany kontroler używa ich wszystkich.

Moje usługi są proste i zawierają tylko wywołania metod z pewną logiką biznesową i interakcją z bazą danych. Są bezpaństwowcami i nie mają pól ani właściwości klasy. Dlatego tworzenie instancji powinno być szybkie, ale zastanawiam się, czy jest to najlepsza praktyka (wiem, że jest to termin obciążony).

+2

Jak zawsze, profil pierwszy. Jednak przypuszczam, że rozwiązywanie zależności jest wolniejsze niż tworzenie ich instancji. –

+0

@insta Wow, nie widziałem lasu przez drzewa. Ale czy Ninject i/lub inne zależności od bufora kontenerów IoC? –

+1

Dodałem poniżej odpowiedź, która powinna ci pomóc ... Już wcześniej wpadłem na ten sam problem. Większość osób (włącznie z mną) nie wie, że można zastąpić fabrykę kontrolera ASP.NET MVC używa do tworzenia kontrolerów. Niestandardowe można ściśle zintegrować pojemnik IoC i buforować zależności, które są potrzebne. –

Odpowiedz

7

każdy wniosek będzie instancji każdą usługę, że moja aplikacja używa, czy specyficzny kontroler wykorzystuje wszystkie im.

Uważam, że sam odpowiedziałeś na swoje pytanie, to nie jest dobre podejście. Ponadto używanie tego rodzaju rozwiązywania zależności (wtrysku serwisowego) jest złym zwyczajem, ponieważ interfejs API kontrolera staje się bałaganiarski. Klienci kontrolerów nie są świadomi, jakie usługi są naprawdę potrzebne dla konkretnego kontrolera, więc możesz skończyć się nieoczekiwanymi błędami czasu wykonywania, testy jednostkowe również będą kłopotliwe.

BTW jeszcze jedna sugestia - zaznacz wszystkie klasy, które są uważane za klasę podstawową przez słowo kluczowe abstract, w ten sposób możesz uniknąć używania go jako konkretnej klasy. Projektowanie i wdrażanie klasy bazowej jest konkretną decyzją projektową, dzięki czemu twoje zamiary projektowe są jasne.

odniesieniu do kosztów instancji, w twoim przypadku to nie duża różnica, ale w ogóle do zmniejszenia kosztów ciężkich przedmiotów instancji można:

  • Zastosowanie Prototype pattern do „uniknąć nieuniknionego koszt tworzenia nowego obiektu w standardowy sposób (np. za pomocą słowa kluczowego "nowy"), gdy jest on zbyt kosztowny dla danej aplikacji " (c) Wikipedia
  • Użyj usługi Lazy Initialization dla usług, które nie są potrzebne od początku czas życia obiektu właściciela, aby zostały one zainicjowane na żądanie. Od .NET Framework 4.0 yo można użyć wbudowanego Lazy(T) class
+0

Dobra odpowiedź, ale chciałbym się trochę bronić. Mój interfejs API kontrolera jest teraz BARDZO czysty, ponieważ wyodrębniłem wszystkie zależności do lokalizatora usług. Mógłbym zrobić bardziej szczegółowy interfejs dla każdego kontrolera, ale dla mojej konkretnej aplikacji/obciążenia jest to przesada. Ponadto nie będę cierpieć z powodu błędów w czasie wykonywania, ponieważ moje testy jednostkowe zapewniają, że kod działa i działa poprawnie. Ale widzę twój punkt widzenia na brak świadomości zależności. Teraz, kiedy to zrobiłem, nie mam łatwego sposobu na poznanie zależności kontrolera (dla własnego odniesienia). Z tym jestem w porządku, na razie. –

+0

OK tak czy inaczej, pamiętaj o tym, – sll

2

Myślę, że rozwiązaniem, którego szukasz, jest użycie fabryki niestandardowych kontrolerów. W ten sposób każdy utworzony kontroler ma dokładnie te zależności, których potrzebuje. Oto jeden dla StructureMap, od 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

Dziękuję za odpowiedź, ale myślę, że już to mam? Poprzednio miałem konfiguratorów konstruktorów kontrolerów do akceptowania interfejsów dla ich zależności usługowych. Ninject i to Bootstrapper, aby to osiągnąć. –

+0

Więc jaki jest sens podstawowego kontrolera, który bierze każdą zależność? Jeśli twoje kontrolery zostały przycięte, aby wziąć tylko argumenty konstruktorów, których potrzebują, jednak są zapełnione, to najlepsze, co możesz zrobić. –

+0

Zamiast więc mieć 10 prywatnych pól, 10 argumentów konstruktora i 10 przydziałów w ciele konstruktora, zajmuję się nim raz w BaseControllerze. W ten sposób, gdy dodaję nową zależność, konstruktory Controller nie będą się zmieniać. Zamiast tego, BaseController otrzyma nowe pole i przypisanie w jego konstruktorze. Podobnie, upraszcza to również moją konfigurację testu. Mam klasę BaseTests, która ustawia pola dla każdej próby w jednym miejscu. –

Powiązane problemy