Słyszę sprzeczne opinie, takie jak:
- „Dedykowane klasy menedżerskie prawie nigdy nie są odpowiednim narzędziem inżynieryjnym”
- „Zajęcia dedykowanego menedżera są (obecnie) najlepszym sposobem na przetrwanie dużego projektu z tysiącami zasobów”
Weźmy klasyczną klasę ResourceManager, która ma następującą funkcjonalność:
- Ładuje zasoby (tekstury, audio, modele 3D itp.)
- Zapewnia, że zasoby są ładowane tylko raz, utrzymując pamięć podręczną
- Odnośnik zlicza zasoby, aby ustalić, czy można je zwolnić
- Ukrywa skąd pochodzą rzeczywiste zasoby (np. Może to być jeden plik na zasób lub wszystkie zasoby w jednym pliku pakietu, lub zasoby mogą być nawet ładowane przez sieć)
- Może przeładowywać zasoby bez ponownego uruchamiania programu, co jest niezwykle przydatne dla artystów pracujących nad grą.
Weźmy również argument „singletony są złe” ze stołu udając, że te obiekty ResourceManager nie są singletonami, a zamiast tego są przekazywane poprzez wstrzykiwanie zależności .
Następnie jest argument „użyj fabryki” lub „nazwij to fabryką”. Mój problem polega na tym, że tak, jest to fabryka, ale jest to również pamięć podręczna i przeładowujący (z powodu braku lepszego słowa). Nazwanie go fabryką nie opisuje go poprawnie, a jeśli sprawię, że będzie to właściwa fabryka, to gdzie zostanie wprowadzone buforowanie i ponowne ładowanie?
Zgadzam się, że klasy „Managera” często są objawem złej architektury, ale w tym konkretnym przypadku, w jaki sposób można je zrestrukturyzować i zachować całą funkcjonalność ? Czy jest to sytuacja, w której klasa „Manager” jest rzeczywiście odpowiednia?
źródło
Odpowiedzi:
Myślę, że problemem nie jest to, że jest to zły projekt. Problem polega na tym, że nazwa „Menedżer” jest nieokreślona, podobnie jak „Aktualizacja”, „Proces” i „Aktor”. Jest to nieprzydatne dla kogoś, kto próbuje zrozumieć ten system i powoduje zamieszanie, jeśli kiedykolwiek masz inne klasy, które wykonują pewne operacje na zasobach.
Jednak nazywanie rzeczy w sposób, który skutecznie przekazuje ich przeznaczenie, jest naprawdę bardzo trudne . Większość systemów jest zbyt skomplikowana, aby ich nazwa była oczywista. Najlepsze, co możesz zrobić, to sprecyzować, który konkretny pomysł sprawia, że jest to klasa spójna, i jakie inne klasy muszą być oczywiście różne, i wybrać unikalne słowo, które pasuje.
IMHO, najważniejszą cechą dobrego imienia jest to, że jest unikalny w kontekście, w którym ludzie go zobaczą (podstawa kodu) i jest łatwy do zapamiętania. Test powinien polegać na tym, że możesz porozmawiać z kolegami z zespołu, którzy znają kod, bez konieczności wyjaśniania, o czym mówisz. Pomoże to również, jeśli kiedykolwiek będziesz musiał napisać dokumentację referencyjną.
Wreszcie, rozważ, że jeśli nie potrafisz opisać tego spójnego pomysłu, może on nie być zbyt spójny. Na przykład, możesz oddzielić buforowanie i liczenie odwołań w AssetCache i zachować ładowanie w AssetLoader. Ale to naprawdę zależy od tego, jak skomplikowany i spleciony jest kod.
Ale jeśli Twój AssetManager jest wystarczająco spójny i nic więcej w twojej grze nie jest AssetManagery, to może to być całkiem dobre imię.
źródło
„Czy robię to w jednym miejscu, czy robię to wiele?”
Ładowanie logiki jest zwykle scentralizowane w jednym punkcie dostępu, ponieważ zwykle działa ona tylko w kluczowych punktach aplikacji, gdzie staramy się ją usunąć jak najszybciej. Zwykle ma to miejsce podczas uruchamiania aplikacji, uruchamiania na poziomie gry lub gdy pozycja gracza na świecie wymaga załadowania nowej porcji, aby zapewnić płynne działanie. Biorąc pod uwagę, że odbywa się to jako proces wsadowy (bez względu na to, czy jest to jedna masywna porcja, czy wiele mniejszych, tak naprawdę nie ma znaczenia), sensowne jest posiadanie jednej metody lub zestawu metod do wywołania tego procesu.
Na większości platform ładowanie jest asynchroniczne, więc właściwie nie masz innego wyboru, jak tylko zachować przepływ kodu do ładowania i inne logiki aplikacji, co jest kolejnym powodem abstrakcji funkcji zarządzania zasobami do ich własnej klasy.
Na koniec kilka punktów do przemyślenia:
Ładowanie zasobów nie jest uruchamiane bardzo często w porównaniu z np. logika gry, więc czy warto w tym celu dodawać złożoności poszczególnym obiektom gry? Obiekty w grze są zwykle utrzymywane możliwie jak najjaśniejsze i są przeznaczone tylko do tego, co jest potrzebne podczas symulacji.
Czy obiekt powinien być odpowiedzialny za swoje stworzenie i zniszczenie? Może to powodować poważne problemy podczas zarządzania jednostką. Jeśli spodziewasz się, że obiekt wykona własny proces tworzenia (w tym uzyskanie zależności od zasobów), to również będzie odpowiedzialny za zniszczenie samego siebie. Może to powodować zwisające / zerowe wskaźniki, więc tak naprawdę trzeba nim zarządzać z zewnątrz. Zobacz tę odpowiedź bardziej szczegółowo opisującą ten problem.
PS Poza zwykłymi argumentami typu „Singletony są okropne” (które są strasznie dogmatyczne), czy kiedykolwiek widziałeś dobry argument przeciwko Menedżerom zasobów? „Dedykowane zajęcia Menedżer prawie nigdy nie są odpowiednim narzędziem inżynierii” nie jest argumentem w ogóle w tym konkretnym przypadku .
źródło