Sądzę, że jest to po części reakcja na niektóre z komentarzy z poprzednich odpowiedzi, ale starałem się zilustrować rozszerzenie niektórych z nich.
Po przejściu do domeny zarządzania długością obiektów wstrzykniętych, prawdopodobnie powinieneś tworzyć fabryki dla tych obiektów.
Podstawowym problemem jest to, że główny składnik kompozycji nie jest świadomy, jaki będzie kontekst środowiskowy wywołania, który musi utworzyć obiekt.
Myślę, że powinienem zrobić krok do tyłu i wyjaśnić w tym miejscu.
Otrzymana mądrość na temat wstrzyknięcia zależnego polega na tym, że w pobliżu punktu wejścia kodu znajduje się pierwiastek kompozycji. Jest wiele dobrych powodów, które nie są trudne do znalezienia w sieci, więc nie będę tutaj wchodził.
Korzeń kompozycji to miejsce, w którym mapujesz interfejsy (zazwyczaj, ale możliwe obiekty) do swoich implantów. Możesz przekazać informacje, które są dostępne w tym momencie do konstruktora. Tak więc możesz przekazać odwołanie do obiektu, którego żywotność jest aktualna w momencie wykonywania głównego katalogu kompozycji.
Jednak, jeśli czas życia katalogu głównego kompozycji nie pokrywa się z czasem życia obiektu, który chcesz utworzyć, musisz odroczyć wykonanie konstruktora, dopóki obiekt nie zostanie utworzony. Dlatego musisz mieć fabrykę. W tym momencie możesz przekazać metodę fabryczną do swojego odwzorowania, a tym samym przekazać informacje potrzebne do wygenerowania obiektu, ale pozwolić na utworzenie w momencie, gdy jest to wymagane, a nie podczas wykonywania głównego katalogu kompozycji.
Nie potrzebujesz klasy fabrycznej, aby to zrobić, metody fabryczne są w porządku, ponadto metoda fabryczna może być wbudowana, więc obciążenie kodu nie jest dużo większe, niż gdybyśmy tworzyli obiekty na trasie kompozycji.
Jeśli mamy projekt z 2 usługami, w których pierwsza usługa jest zależna od pierwszej i chcemy tylko, aby czas życia drugiej usługi był uruchamiany, gdy tworzymy pierwszą usługę, możemy mieć coś takiego. (Używam ninject dać przykład kodu, ale spodziewam się, że pozostałe pojemniki MKOl działają podobnie w tym zakresie).
`
public class Service1:IService
{
private Func<IService>serviceFactoryMethod _Service2Factory;
public Service1(Func<IService>service2FactoryMethod)
{
_Service2Factory=service2FactoryMethod;
}
public void DoSomethingUsingService2()
{
var service2=_Service2Factory();
service2.DoSomething();
}
}
public class MainClass
{
public void CompositionRoot()
{
var kernel= new StandardKernel();
kernel.Bind.ToMethod(m=>
{
return new Service1(m.Kernel.Get<IService2>());
}
}
}
`
Ten przykład nie odnosi się w jaki sposób zarządzać żywotność App , czas życia graczy i gier, ale mam nadzieję, że daje on wystarczające wskazówki, jak usunąć problemy z życia związane z zastrzykiem uzależnienia.
Uwaga boczna: w przypadku korzystania z programu Ninject użytkownik może zmienić zakres usługi Service2, aby zarządzać czasem jego istnienia, tak aby trwał przez cały okres użytkowania usługi Service1. Na przykład, jeśli wiesz, że każde wystąpienie gry miało się zdarzyć w jego własnym wątku (OK, może to być może trochę nieprawdopodobne), możesz użyć InThreadScope do gry.
Konfiguracja stylu życia/życia jest zwykle czymś, co obsługuje większość kontenerów DI. O jakiej platformie i ramach DI mówisz? – Steven
Mam świadomość, że niektóre kontenery obsługują dożywotnio zarządzanie w pewnym zakresie, ale wyobraź sobie klasę, która jako parametr przyjmuje parametr IPlayer (tak jak wiele klas robi w tym przypadku). Jeśli istnieje jeden kontener, to w jaki sposób zarejestrujesz tę klasę bez konieczności posiadania fabryki dla danych środowiska wykonawczego? Eksperymentowałem z tworzeniem oddzielnych pojemników dla każdego cyklu życia, ale wciąż staram się łączyć różne elementy, gdy obawy dotyczą całego okresu życia. –
W tym przypadku .NET/C# jednak tak naprawdę jestem zainteresowany tym, jak ludzie rozwiązują ten problem projektowy bardziej ogólnie. W szczególności nie chcę polegać zbytnio na danym kontenerze, ponieważ może nie być dostępny na każdej platformie, na którą kieruje. –