Ich höre widersprüchliche Meinungen wie:
- "Engagierte Manager-Klassen sind so gut wie nie das richtige Engineering-Tool."
- "Spezielle Manager-Kurse sind (derzeit) der beste Weg, um ein großes Projekt mit Tausenden von Ressourcen zu überleben."
Nehmen wir eine klassische ResourceManager-Klasse mit den folgenden Funktionen:
- Lädt Assets (Texturen, Audio, 3D-Modelle usw.)
- Stellt sicher, dass Assets nur einmal geladen werden, indem ein Cache aufbewahrt wird
- Die Referenz zählt die Vermögenswerte, um festzustellen, ob sie freigegeben werden können
- Versteckt, woher die tatsächlichen Assets stammen (z. B. eine Datei pro Asset oder alle Assets in einer Paketdatei oder Assets können sogar über das Netzwerk geladen werden)
- Kann Assets nachladen, ohne das Programm neu zu starten, was für die am Spiel arbeitenden Künstler äußerst nützlich ist.
Nehmen wir auch das Argument "Singletons sind schlecht" vom Tisch, indem wir so tun, als wären diese ResourceManager-Objekte keine Singletons und würden stattdessen per Abhängigkeitsinjektion weitergegeben .
Dann gibt es das Argument "Fabrik verwenden" oder "Fabrik nennen". Mein Problem dabei ist, dass es sich zwar um eine Fabrik handelt, aber auch um einen Cache und einen Reloader (mangels eines besseren Wortes). Wenn ich es eine Factory nenne, wird es nicht richtig beschrieben, und wenn ich es zu einer richtigen Factory mache, wo wird dann das Caching und das Neuladen implementiert?
Ich bin damit einverstanden, dass "Manager" -Klassen oft ein Symptom für eine schlechte Architektur sind, aber wie könnte sie in diesem speziellen Fall umstrukturiert werden und dennoch die gesamte Funktionalität behalten ? Ist dies eine Situation, in der eine "Manager" -Klasse tatsächlich angemessen ist?
quelle
Antworten:
Ich denke, das Problem ist nicht, dass dies ein schlechtes Design ist. Das Problem ist, dass der Name "Manager" nicht eindeutig ist, wie "Update" und "Process" und "Actor". Es ist nicht hilfreich für jemanden, der versucht, dieses System zu verstehen, und es schafft Verwirrung, wenn Sie jemals andere Klassen haben, die Operationen an Assets ausführen.
Es ist jedoch sehr, sehr schwierig , Dinge so zu benennen, dass sie ihren Zweck effizient wiedergeben . Die meisten Systeme sind zu kompliziert, um durch ihren Namen erkennbar zu werden. Das Beste, was Sie tun können, ist, einzugrenzen, welche bestimmte Idee dies zu einer zusammenhängenden Klasse macht und welche anderen Klassen offensichtlich anders sein müssen, und ein eindeutiges Wort zu wählen, das passt.
Meiner Meinung nach ist das wichtigste Merkmal eines guten Namens, dass es innerhalb des Kontexts, in dem die Leute es sehen werden (die Codebasis), einzigartig ist und dass es leicht zu merken ist. Der Test sollte sein, dass Sie ein Gespräch mit Ihren Teamkollegen führen können, die mit dem Code vertraut sind, ohne zu klären, worauf Sie sich beziehen. Dies würde auch helfen, wenn Sie jemals Referenzdokumentation schreiben müssen.
Bedenken Sie schließlich, dass diese zusammenhängende Idee möglicherweise nicht sehr zusammenhängend ist, wenn Sie sie nicht beschreiben können. Beispielsweise können Sie die Caching- und Referenzierungszählung in einem AssetCache trennen und das Laden in einem AssetLoader beibehalten. Aber das hängt wirklich davon ab, wie kompliziert und verflochten der Code ist.
Aber wenn Ihr AssetManager kohärent genug ist und nichts anderes in Ihrem Spiel AssetManagery ist, könnte es ein perfekter Name sein.
quelle
"Mache ich das an einem Ort oder mache ich es an vielen?"
Die Ladelogik wird normalerweise an einem einzigen Zugriffspunkt zentralisiert, da sie in der Regel nur an wichtigen Punkten in der Anwendung ausgeführt wird, an denen wir versuchen, sie so schnell wie möglich aus dem Weg zu räumen. Dies geschieht normalerweise beim Start der App, beim Starten auf Spielebene oder wenn die Position des Spielers auf der Welt das Laden eines neuen Blocks erfordert, um das Spielerlebnis nahtlos zu halten. In Anbetracht dessen, dass dies als Batch-Prozess durchgeführt wird (ob in einem massiven Block oder in vielen kleineren, spielt es keine Rolle), ist es sinnvoll, eine Methode oder eine Gruppe von Methoden aufzurufen, um diesen Prozess zu starten.
Auf den meisten Plattformen ist das Laden asynchron, sodass Sie eigentlich keine andere Wahl haben, als die Codeflüsse für das Laden und andere Anwendungslogiken getrennt zu halten. Dies ist ein weiterer Grund für die Abstraktion von Ressourcenverwaltungsfunktionen in ihre eigene Klasse.
Abschließend einige Punkte, über die man nachdenken sollte:
Das Laden von Ressourcen wird im Vergleich zu z. Spielelogik, lohnt es sich also, die Komplexität Ihrer einzelnen Spielobjekte zu erhöhen? Spielobjekte werden normalerweise so leicht wie möglich gehalten und sind nur für das vorgesehen, was während der Simulation benötigt wird.
Sollte ein Objekt für seine eigene Schöpfung und Zerstörung verantwortlich sein? Dies kann bei der Verwaltung von Entitäten zu erheblichen Problemen führen. Wenn Sie erwarten, dass ein Objekt seinen eigenen Erstellungsprozess ausführt (einschließlich des Erhaltens von Ressourcenabhängigkeiten), ist es ebenfalls dafür verantwortlich, sich selbst zu zerstören. Dies kann zu Dangling / Null-Zeigern führen, daher muss es wirklich von außen verwaltet werden. In dieser Antwort wird das Problem detaillierter beschrieben.
PS Abgesehen von den üblichen Argumenten vom Typ "Singletons sind schrecklich" (die fürchterlich dogmatisch sind), haben Sie jemals ein gutes Argument gegen ResourceManager gesehen? "Dedizierte Manager-Klassen sind so gut wie nie das richtige Engineering-Tool" ist in diesem speziellen Fall überhaupt kein Argument .
quelle