2012-01-26 15 views
6

Okay, tak niedawno czytałem w ninject, ale mam problem ze zrozumieniem, co sprawia, że ​​jest to lepsze od tego, dlaczego polecono je jako "DI" biednego człowieka na stronie wiki. Smutne jest to, podszedłem wszystkich swoich stron na wiki i nadal nie rozumiem = (Masz problemy ze zrozumieniem ninject (lub po prostu pojemnik IOC w ogóle) nad fabryczną DI?

Zazwyczaj będę owijać moich klas usług we wzór fabryki, który obsługuje DI tak:.

public static class SomeTypeServiceFactory 
{ 
    public static SomeTypeService GetService() 
    { 
     SomeTypeRepository someTypeRepository = new SomeTypeRepository(); 
     return = new SomeTypeService(someTypeRepository); 

    } 

} 

które mi wydaje się trochę jak moduły:

public class WarriorModule : NinjectModule { 
    public override void Load() { 
     Bind<IWeapon>().To<Sword>(); 
     Bind<Samurai>().ToSelf().InSingletonScope(); 
    } 
} 

gdzie każda klasa będzie mieć to moduł związany i Bind to konstruktora do konkretnej realizacji Chociaż kod ninject jest 1 mniej linia ja po prostu nie widzi. przewagę, za każdym razem, gdy dodajesz/usuwasz konstruktorów lub zmieniasz implementacja konstruktora interfejsu, musielibyście zmienić moduł w taki sam sposób, jak w fabryce? Więc nie widzę tutaj przewagi.

Wtedy pomyślałem mogłem wymyślić generycznego konferencyjnym fabryce w oparciu tak:

public static TServiceClass GetService<TServiceClass>() 
     where TServiceClass : class 
    { 
     TServiceClass serviceClass = null; 

     string repositoryName = typeof(TServiceClass).ToString().Replace("Service", "Repository"); 
     Type repositoryType = Type.GetType(repositoryName); 

     if (repositoryType != null) 
     { 
      object repository = Activator.CreateInstance(repositoryType); 
      serviceClass = (TServiceClass)Activator.CreateInstance(typeof (TServiceClass), new[]{repository}); 
     } 

     return serviceClass; 
    } 

jednak jest to bzdura dla 2 powodów: 1) Jest ściśle zależne od konwencji nazewnictwa, 2) założonej repozytorium nigdy nie będzie miało żadnych konstruktorów (nie będzie to prawda), a jedynym konstruktorem usługi będzie odpowiadające repo (również nie prawdziwe). Powiedziano mi, "hej, to jest miejsce, w którym powinieneś użyć kontenera IoC, byłoby świetnie tutaj!" I tak moje badania zaczęły się ... ale ja po prostu nie widzę tego i mam problem ze zrozumieniem ...

Czy istnieje sposób, w jaki program Ninject może automatycznie rozwiązać konstruktorów klasy bez określonej deklaracji, tak aby był Świetne do wykorzystania w mojej generycznej fabryce (zdaję sobie również sprawę, że mogłem to zrobić ręcznie za pomocą refleksji, ale to jest hit wydajnościowy, a ninject mówi, że na ich stronie nie używają refleksji).

Oświecenie w tej kwestii i/lub pokazanie, jak można go wykorzystać w mojej fabryce generycznej, byłoby bardzo docenione!

EDIT: Odpowiedź

So dzięki wyjaśnienie poniżej byłem sprawnie, aby w pełni zrozumieć awesomeness ninject i mój rodzajowa fabryka wygląda następująco:

public static class EntityServiceFactory 
{ 
    public static TServiceClass GetService<TServiceClass>() 
     where TServiceClass : class 
    { 
     IKernel kernel = new StandardKernel(); 

     return kernel.Get<TServiceClass>(); 
    } 
} 

dość niesamowite. Wszystko jest obsługiwane automatycznie, ponieważ konkretne klasy mają domyślne powiązanie.

+0

Zwykły zapisany komentarz dotyczący rekordu: przejdź do [Injection Injection in .NET book my Mark Seemann] (http.commanning.com/seemann). Nie mogę sobie wyobrazić, że nie masz pewności, dlaczego i jak DI (wzór) i kontenery DI w ciągu tygodnia od posiadania książki. –

Odpowiedz

7

Korzyści z kontenerów IoC rosną wraz z rozmiarem projektu. W przypadku małych projektów ich korzyść w porównaniu do "Poor Man's DI", tak jak w twojej fabryce, jest minimalna. Wyobraź sobie duży projekt, który ma tysiące klas, a niektóre usługi są używane w wielu klasach. W takim przypadku wystarczy powiedziec, jak tylko rozwiazane zostana te uslugi. W fabryce musisz robić to raz za razem dla każdej klasy.

Przykład: Jeśli masz usługę MyService : IMyService i klasę A wymagającego IMyService trzeba powiedzieć Ninject jak powinno to rozwiązać tego typu jak w fabryce. Tutaj korzyść jest minimalna. Ale gdy tylko projekt się powiększy i dodasz klasę B, która również zależy od IMyService, musisz po prostu powiedzieć Ninject, jak rozwiązać B. Ninject wie już, jak uzyskać IMyService. Z drugiej strony, w fabryce trzeba jeszcze raz zdefiniować, jak B otrzymuje numer IMyService.

Aby zrobić jeszcze więcej. W większości przypadków nie powinieneś definiować powiązań jeden po drugim. Zamiast tego użyj konfiguracji opartej na konwencjach (Ninject.Extension.Conventions). Dzięki temu możesz grupować klasy razem (Usługi, Repozytoria, Kontrolery, Prezenterzy, Widoki, ....) i konfigurować je w ten sam sposób. Na przykład. powiedz Ninject, że wszystkie klasy, które kończą się na Service, będą pojedyncza i opublikują wszystkie ich interfejsy. W ten sposób masz jedną pojedynczą konfigurację i żadna zmiana nie jest wymagana, gdy dodajesz inną usługę.

Kontenery IoC to nie tylko fabryki. Jest o wiele więcej. Na przykład. Zarządzanie cyklem życia, przechwytywanie, ...

kernel.Bind(
    x => x.FromThisAssembly() 
      .SelectAllClasses() 
      .InNamespace("Services") 
      .BindToAllInterfaces() 
      .Configure(b => b.InSingletonScope())); 
kernel.Bind(
    x => x.FromThisAssembly() 
      .SelectAllClasses() 
      .InNamespace("Repositories") 
      .BindToAllInterfaces()); 
+0

Widzę (to samo pytanie, jak w przypadku drugiej odpowiedzi), więc naprawdę ninject nie pomoże mi w wykonaniu ogólnej produkcji fabryki? Lub w jakiś sposób automatycznie rozwiązać zależności beze mnie, gdybym oświadczył je? O ile używa się go, aby nie mieć modułu/fabryki dla każdej pojedynczej klasy usług. Co się stanie, jeśli moje repozytorium i usługi będą miały różną liczbę zastrzyków, z których nie można naprawdę korzystać z konwencji? – SventoryMang

+1

Wygląda na to, że nie rozumiesz, jak działa ninject. Sprawdza konstruktor, a następnie próbuje uzyskać właściwe zależności od konfiguracji. Dlatego klasy o różnej liczbie zależności można łatwo skonfigurować przy użyciu tej samej konwencji. –

+0

Hmm ja * myślę * Teraz rozumiem. Dlatego nie może mi pomóc w mojej fabryce generycznej, prawda? Nadal muszę w pewnym momencie skonfigurować deklaracje iniekcyjne, co oznacza, że ​​nie mogę tutaj zrobić generycznego. Czy masz przykład użycia konwencji ze zmienną liczbą zależności? Przepraszam, że jestem tu tak gęsty = (Mam trudny czas, ekstrapolując to, co jest na stronie do mojego własnego scenariusza, – SventoryMang

2

Aby być w pełni analogiczna kod fabryczny powinien brzmieć:

public static class SomeTypeServiceFactory 
{ 
    public static ISomeTypeService GetService() 
    { 
     SomeTypeRepository someTypeRepository = new SomeTypeRepository(); 

     // Somewhere in here I need to figure out if i'm in testing mode 
     // and i have to do this in a scope which is not in the setup of my 
      // unit tests 

     return new SomeTypeService(someTypeRepository); 
    } 

    private static ISomeTypeService GetServiceForTesting() 
    { 
     SomeTypeRepository someTypeRepository = new SomeTypeRepository(); 
     return new SomeTestingTypeService(someTypeRepository); 
    } 
} 

A equilvalent w Ninject byłoby:

public class WarriorModule : NinjectModule { 
    public override void Load() { 
     Bind<ISomeTypeService>().To<SomeTypeService>(); 
    } 
} 

public class TestingWarriorModule : NinjectModule { 
    public override void Load() { 
     Bind<ISomeTypeService>().To<SomeTestingTypeService>(); 
    } 
} 

Tutaj można zdefiniować zależności deklaratywnie, zapewniając, że jedyne różnice pomiędzy twoim testowaniem a kodem produkcyjnym jest zawarty w fazie instalacji.

Zaletą IoC nie jest to, że nie trzeba zmieniać modułu za każdym razem, gdy zmienia się interfejs lub konstruktor, to fakt, że można deklarować zależności w sposób deklaratywny oraz że można podłączać i odtwarzać różne moduły dla różnych cele.

+0

Rozumiem, więc naprawdę nie pomoże mi to w ogólnej implementacji fabryki? Lub w jakiś sposób automatycznie rozwiązać zależności beze mnie, gdybym oświadczył je? O ile używa się go, aby nie mieć modułu/fabryki dla każdej pojedynczej klasy usług. – SventoryMang

Powiązane problemy