Teraz nie widzę w tym nic złego ani niczego, co mogłoby powodować problemy, ale dopiero zacząłem używać klas statycznych, więc czy ktoś bardziej kompetentny widzi jakiś gigantyczny powód, dla którego to zły pomysł?
Kiedy masz błyszczący nowy młotek, każdy problem wygląda jak gwóźdź.
Ogólnie rzecz biorąc, nie ma nic złego w klasach statycznych i / lub metodach, jeśli są one właściwie stosowane (dla rzeczy, które nie mają stanu zależnego od instancji lub od niego zależą). Jednak w twoim przypadku niewłaściwie je wykorzystujesz, aby ukryć zależność od instancji, myląc to z usunięciem zależności. Wydaje się również, że ujawniasz szczegóły implementacji Game1
klasy, co również jest ogólnie złe.
Oto sedno problemu:
... jeśli jestem w środku AnimalHandler
i chcę sprawdzić, czy można TileHandler
odtąd chodzić po kafelku,
co powoduje problemy, lub muszę przekazać listę płytek AnimalHandler
, na które można chodzić , czego wolałbym nie robić.
Ignorowanie możliwości, że AnimalHandler
potrzebowanie tych kafelków może samo w sobie być złym projektem (z wybranymi nazwami trudno jest podać szczegóły tych klas) na razie ... jeśli AnimalHandler
potrzebna jest lista płytek dostępnych do przejścia, to potrzebna jest lista płytki spacerowe. Zasadniczo lepiej jest uczynić zależności bardziej wyraźnymi niż mniej , ponieważ dzięki temu kod staje się bardziej samodokumentujący. Przekazując listę bezpośrednio do AnimalHandler
, wyraźnie zaznaczasz, że ona potrzebuje takiej listy. Jeśli zamiast tego uczynisz wszystko statycznym i publicznym, abyś mógł po prostu uzyskać dostęp do listy statycznej przechowywanej gdzie indziej w kodzie, wystarczy ukryć zależność bez faktycznego jej rozwiązania lub usunięcia.
W przypadku małej gry, która nie wymaga skalowania, nie będzie to problemem samo w sobie, ale może poprowadzić cię na ścieżkę złego nawyku, więc możesz rozważyć, aby tego nie robić. Przynajmniej pamiętaj o tym przy następnym projekcie, nad którym pracujesz.
Powodem, dla którego wywoływanie TileHandler w kontekście statycznym nie jest najlepszym możliwym projektem, jest to, że łączy on elementy twojego projektu, które w innym przypadku mogłyby zostać oddzielone.
Jeśli zdecydujesz się na więcej niż jednego TileHandlera w przyszłości, będziesz musiał wykonać wiele pracy, aby uwzględnić tę zmianę.
Jeśli zdecydujesz się usunąć TileHandler, będziesz musiał wykonać wiele pracy, aby uwzględnić tę zmianę.
Załóżmy, że w przyszłości zbudujesz inny poziom / strefę, która obsługuje płytki w inny sposób niż twój obecny TileHandler. Następnie musisz mieć sposób na określenie metody obsługi kafelków, którą chcesz zastosować, lub musisz zadzwonić do innego modułu obsługi.
Jeśli TileHandler został przekazany jako parametr do obiektów, które go wykorzystują, wówczas możesz po prostu przekazać inny raz następnym razem lub ustawić inny moduł obsługi kafelków na obiektach, które go wykorzystają później.
Osobiście uzyskuję dostęp do wielu rzeczy w moich grach XNA ze statycznego kontekstu i zakładam, że nigdy nie będę mieć więcej niż jedną z nich.
Jeśli chcesz ponownie użyć kodu silnika gry w następnej grze, prawdopodobnie będziesz musiał przepisać wiele rzeczy, które obecnie zapisałeś jako statyczne.
W skrócie:
Na korzyść niestosowania kontekstu statycznego:
Przekazywanie obiektów w jak największym stopniu oddziela elementy gry i pozwala na łatwiejszą modyfikację / ponowne użycie ich w bieżących lub przyszłych projektach. Pozwala także nieco łatwiej zarządzać złożonością dużych ilości kodu (pomyśl o setkach statycznych menedżerów w swojej klasie gier, w dużej grze).
Na korzyść statycznego kontekstu:
Deklarowanie i uzyskiwanie dostępu do obiektów ze statycznego kontekstu ułatwia pisanie małych gier, które nie wymagają setek statycznych menedżerów. Upraszcza wiele metod i konstruktorów, nie wymagając jednego lub więcej dodatkowych parametrów, do których dostęp jest uzyskiwany statycznie.
źródło
Nie sądzę, że jest to bardzo zły pomysł na prostą grę, ale możesz również zajrzeć na http://www.nuclex.org/articles/4-architecture/6-game-components-and-game-services dla lepszy pomysł na budowanie wzajemnie komunikujących się elementów gry
źródło
Takie rzeczy jak TileHandler i AnimalHandler Umieściłem poziom wyżej na ekranie gry. Czy ekran tytułowy wymaga dostępu do TileHandler i czy jest inicjowany przy pierwszym załadowaniu gry? Prawdopodobnie nie.
Sprawdź przykład XNA State Management . Zawiera dużo kodu, ale w zasadzie gra podstawowa inicjuje stos stanów gry (lub ekranów). Każdy ekran jest dość niezależny od innych i działa jako uproszczona wersja samej gry. Twój PlayScreen może mieć elementy statyczne, aby były dostępne dla komponentów PlayScreen.
W podstawowej grze używam kilku statystyk, ale są to rzeczy bardzo niskiego poziomu, takie jak czytniki InputHelper, Log lub Config. Są dość standardowe we wszystkich grach, więc silnik podstawowy można szybko i łatwo przenieść. Ekrany są miejscem, w którym dzieje się logika gry. Tak krótka odpowiedź - nie, nie sądzę, że to zły pomysł w teorii, po prostu uważaj, co robisz statycznie. Gdy zmienisz zdanie, zrobienie czegoś statycznego jest ogromną pracą.
źródło
Punkty podniesione tutaj są dobre. Z mojego doświadczenia (które podobno bardziej zależy od aplikacji biznesowych niż gier), są świetne zastosowania dla klas statycznych i członków i korzystałem z nich wiele razy. Przekonałem się, że wraz ze wzrostem wymagań i złożoności w końcu przetwarzam te klasy statyczne i przekształcam je w klasy instancji i zaczynam je przekazywać.
Chciałbym powiedzieć, że jeśli użycie klasy statycznej pomaga wydostać się z tej gry, idź do niej, ale nadal rób właściwe rzeczy: zaimplementuj interfejs lub klasę podstawową, aby łatwiej było ją zgrać i przekonwertować później do klasy instancji.
Uncja profilaktyki jest warta funta lekarstwa, więc upewnij się, że twoja klasa statyczna nie wiąże cię, co utrudnia zmianę. Refaktoryzacja metody za pomocą klasy statycznej, która implementuje interfejs, jest łatwa, więc akceptuje nowy parametr interfejsu i używa tego interfejsu zamiast odwołania do klasy statycznej.
źródło
Tak, ogólnie jest to zawsze zły pomysł.
Przekształcanie obiektów zawierających zmieniające się dane (tj. Niczego oprócz stałych tylko do odczytu i tabel odnośników) w klasy statyczne to miejsce, w którym dobry projekt wymaga nurkowania.
Promuje przypadkowe zależności, które zabijają modułowość i uniemożliwiają ponowne użycie kodu. Załóżmy, że chciałeś napisać edytor do swojej gry - nagle miałbyś mnóstwo klas płaczących o coś
Game1
, czego nie można łatwo przenieść do wspólnej biblioteki.Twój kod staje się niestabilny. Testowanie jednostkowe polega na izolowaniu poszczególnych klas od reszty poprzez wyśmiewanie lub symulowanie ich zależności (które należy ograniczyć do minimum). Każda klasa statyczna jest odpowiedzialnością, ponieważ można do niej uzyskać dostęp w dowolnym momencie, przeprowadzić stan w wielu testach lub wymagać zainicjowania przed testem, który się powiedzie.
Ukrywa zależności. Podobnie jak anty-wzorzec dostawcy usług (również stosowany przez XNA, Game.Services), twoje klasy mogą wybierać zależności, których nie widać na zewnątrz.
Takie podejście staje się szczególnie trujące, jeśli łączy się klasy statyczne z wywołaniami pociągów towarowych (rzeczy
Game.Instance.ActorManager.Enemies.FindInRange(10)
- tak zwane ze względu na symbole łańcuchowe podobne do wagonów pociągowych), w których komponenty nagle nie tylko wymagająGame
klasy, ale takżeInstance
właściwości statycznej, która zwraca coś zActorManager
właściwość, która maEnemies
właściwość, która zwraca obiekt zFindInRange()
metody.Jedyną wymówką, którą przyjąłbym do pisania zmiennych klas statycznych, jest to, że wciąż się uczy i nie jest w stanie konsekwentnie stosować dobrego projektu i wyszkolonego oka na wykrywanie złych wyborów.
źródło