Zależność Wtrysk i produktywność

Abstrakcyjny

Od kilku miesięcy programuję lekki silnik oparty na C # z abstrakcją API i systemem encji / komponentów / skryptów. Cała idea polega na ułatwieniu procesu tworzenia gier w XNA, SlimDX i innych, zapewniając architekturę podobną do silnika Unity.

Wyzwania projektowe

Jak większość twórców gier wie, jest wiele różnychusługi musisz uzyskać dostęp do całego kodu. Wielu programistów korzysta z globalnych statycznych instancji np. menedżer renderowania (lub kompozytor), scena, urządzenie graficzne (DX), rejestrator, stan wejściowy, rzutnia, okno i tak dalej. Istnieją alternatywne podejścia do globalnych statycznych instancji / singletonów. Jednym z nich jest nadanie każdej klasie instancji klas, do których potrzebuje dostępu, poprzez konstruktor lub wtrysk zależności konstruktora / właściwości (DI), innym jest użycie globalnego lokalizatora usług, takiego jak ObjectFactory StructureMap, gdzie lokalizator usługi jest zwykle skonfigurowany jako kontener IoC.

Zastrzyk uzależnienia

Zdecydowałem się pójść drogą DI z wielu powodów. Najbardziej oczywistym z nich jest testowalność, programowanie w oparciu o interfejsy i posiadanie wszystkich zależności każdej klasy udostępnianej im przez konstruktora, te klasy są łatwe do przetestowania, ponieważ kontener testowy może utworzyć instancję wymaganych usług lub ich prób i wprowadzić do każda klasa do testowania. Innym powodem robienia DI / IoC było, wierzcie lub nie, zwiększenie czytelności kodu. Nigdy więcej ogromnego procesu inicjalizacji tworzenia instancji wszystkich różnych usług i ręcznego tworzenia instancji klas z odniesieniami do wymaganych usług. Konfiguracja jądra (NInject) / rejestru (StructureMap) zapewnia wygodny punkt konfiguracji dla silnika / gry, gdzie implementacje usług są wybierane i konfigurowane.

Moje problemy

Często czuję, że tworzę interfejsy do sake interfejsówMoja produktywność drastycznie spadła, ponieważ wszystko, co robię, to martwienie się o to, jak robić rzeczy w sposób DI, zamiast szybkiego i prostegoglobalny statyczny sposób.W niektórych przypadkach, np. podczas tworzenia instancji nowych elementów w czasie wykonywania potrzebny jest dostęp do kontenera / jądra IoC w celu utworzenia instancji. Stwarza to zależność od samego kontenera IoC(ObjectFactory w SM, instancja jądra w Ninject), co naprawdę jest sprzeczne z powodem, dla którego używa się go w pierwszej kolejności. Jak można to rozwiązać? Przychodzą na myśl abstrakcyjne fabryki, ale to jeszcze bardziej komplikuje kod.W zależności od wymagań usługi, niektóre konstruktory klas mogą stać się bardzo duże, co uczyni klasę całkowicie bezużyteczną w innych kontekstach, gdzie i jeśli IoC nie jest używane.

Zasadniczo działanie DI / IoC znacznie spowalnia moją wydajność, aw niektórych przypadkach dodatkowo komplikuje kod i architekturę. Dlatego nie jestem pewien, czy jest to ścieżka, którą powinienem podążać, czy po prostu zrezygnuję i zrobię rzeczy w staroświecki sposób. Nie szukam pojedynczej odpowiedzi, która mówi, co powinienem lub nie powinienem robić, ale dyskusja na temat tego, czy używanie DI jest tego warte na dłuższą metę, w przeciwieństwie do stosowania globalnej metody statycznej / pojedynczej, możliwe zalety i wady, które przeoczyłem możliwe rozwiązania moich problemów wymienionych powyżej, gdy mamy do czynienia z DI.

questionAnswers(1)

yourAnswerToTheQuestion