Microsoft.Xna.Framework.Game
Klasa ma Services właściwość, która pozwala programiście dodać usługę do swojej gry poprzez dostarczanie rodzaj klasy i instancję klasy do metody Add.
Teraz zamiast przekazywać AudioComponent
do wszystkich klas i metod, które tego wymagają, wystarczy przekazać Game
instancję i wyszukać usługę. (Lokalizator usług )
Ponieważ gry mają wiele usług (GraphicsDevice, SceneGraph, AudioComponent, EffectsManager, itd.), Teraz zasadniczo będziesz przekazywać grę do wszystkiego.
Dlaczego więc nie uczynić z tych przypadków singletonów? Cóż, ponieważ Singletony są złe, ponieważ mają stan globalny, zapobiegają testowaniu i sprawiają, że projekt jest znacznie bardziej kruchy. Lokalizatory usług są równie uważane za anty-wzorzec dla wielu, ponieważ zamiast przekazywać zależność od obiektu, podajesz lokalizator usług (Gra), który łączy tę klasę z resztą usług.
Dlaczego więc Usługi są zalecane w XNA i tworzeniu gier? Czy to dlatego, że gry różnią się od zwykłych programów i są ściśle powiązane ze swoimi komponentami, a konieczność przejścia każdego komponentu niezbędnego do funkcjonowania klasy byłaby bardzo uciążliwa? Czy usługi gier są zatem niezbędnym złem w projektowaniu gier? Czy istnieją alternatywy, które nie wymagają długich list parametrów i łączenia?
źródło
Odpowiedzi:
Nie sądzę, aby wszyscy zgadzali się, że lokalizatory usług są złe. Lokalizatory usług zapewniają sposób na oddzielenie ważnej funkcjonalności, której wszyscy potrzebują od ich rzeczywistej implementacji. Lokalizatory usług umożliwiają także wymianę usług w czasie wykonywania. Nie sądzę też, że to prawda, że musisz wszędzie wokół znaleźć lokalizator usług. Myślę, że możesz uzyskać do niego dostęp z dowolnego miejsca. Podczas gdy klasa gry z globalsami musiałaby być przekazywana około tysiąca razy na klatkę (co spowodowałoby złą wydajność).
Aby nieco rozróżnić lokalizator usług od klasy z globalsami, rozważ następujący przykład:
Tworzę grę i używam obiektu klasy Game, który ma zmienną globalną: moduł ładujący zawartość. Teraz w mojej następnej grze nie chcę korzystać z klasy gameA, ale tworzę nową klasę gameB. Muszę teraz ponownie dodać globały gameA do gameB, co jest dodatkową pracą. Również staje się trudne skonfigurowanie typu modułu ładującego treści, który chcę. Powiedzmy, że mam grę, która działa zarówno na PC, jak i na XBOX. Na komputerze chcę moduł ładujący treści, który może również otworzyć okno dialogowe „otwórz plik”. Będąc na XBOX zdecydowanie tego nie chcę. Mając plik konfiguracyjny, mogę nawet w połowie gry łatwo zmienić moduł ładujący zawartość, nawet skądinąd klasy GameA, bez upubliczniania globałów w gameA.
Rozważmy teraz, że używam lokalizatora usług. Zawsze mogę go używać. Nawet rodzaje usług mogą być różne przez cały czas. Prawdą jest również to, że nie będę nawet dbał o ich implementację, o ile mają one wspólny interfejs. (Chociaż mógłbym użyć tego również w klasie typu gamA).
W każdym razie myślę, że usługi gier będą dla ciebie bardzo przydatne. Wszyscy, których znam, używają tego. Aby ci trochę pomóc. Stworzyłem małą klasę pomocników wokół usług gier, dzięki czemu możesz cały czas robić o wiele mniej: http://roy-t.nl/index.php/2010/08/25/xna-accessing-contentmanager -i-grafika-urządzenie-gdziekolwiek-kiedykolwiek-gra-serwisowy pojemnik / Używam go dość często.
źródło
return (T)Instance.GetService(typeof(T));
.Service
sufiks na końcu każdej metody.AddService
metoda Services przyjmuje typ, jest to, że możesz określić interfejs usługi. Na przykładServices.AddService(typeof(IGraphicsDeviceManager), graphics);
. Następnie podczas pobierania usługi możesz określić interfejs jako typ i rzutować go na wybraną podklasę.Singletony na ogół mają wiele przydatnych cech i łączą je razem w okropną hybrydę, która daje ci kilka rzeczy, których nie chcesz wraz z tym, co chcesz. (Czy miało to charakterystykę tworzenia na żądanie? Zakres globalny? Egzekwowanie co najmniej jednej instancji? Zakaz wielu instancji?)
Nie można całkowicie uniknąć sprzężenia. Rzeczy używają innych rzeczy, a bez tego twój program nic nie robi. Tak więc jedynym prawdziwym pytaniem jest, na jakim poziomie abstrakcji jest.
Większość tekstów o orientacji obiektowej rozróżnia kompozycję i agregację. Ważne jest, aby znać koncepcyjną różnicę między czymś, co posiadasz, a czymś, o czym wiesz. Niestety większość współczesnych języków nie ma tutaj wyraźnego rozróżnienia, a odniesienie do obiektu może oznaczać jedną z tych rzeczy. (Jak na ironię, C ++ działa lepiej, jeśli używasz różnych inteligentnych typów wskaźników).
Jednym ze sposobów, dzięki którym można wyczyścić skład i agregację w kodzie, jest użycie usług dla obiektów agregowanych. Usługi to jeden ze sposobów zapewnienia dostępu do rzeczy, których nie posiadasz, ale z których możesz korzystać.
Nie sądzę, że są one powszechnie zalecane w tworzeniu gier.
źródło