Trennung von Logik und Daten im Browsergame

8

Ich habe tagelang darüber nachgedacht und bin mir immer noch nicht sicher, was ich tun soll. Ich versuche, ein Kampfsystem in PHP umzugestalten (... sorry.) Folgendes existiert bisher:

  • Es gibt zwei (bisher) Arten von Entitäten, die am Kampf teilnehmen können. Nennen wir sie einfach Spieler und NPCs. Ihre Daten sind bereits ziemlich gut geschrieben.
  • Wenn diese Entitäten in einen Kampf verwickelt sind, werden sie mit einem anderen Objekt in der Datenbank umhüllt Combatant, das als a bezeichnet wird und ihnen Informationen über den jeweiligen Kampf gibt. Sie können an mehreren Kämpfen gleichzeitig beteiligt sein.
  • Ich versuche, die Logik-Engine für den Kampf zu schreiben, indem ich sie von Kämpfern injizieren lasse.
  • Ich möchte in der Lage sein, alles zum Testen zu verspotten.

Um Logik und Daten zu trennen, möchte ich zwei Schnittstellen / Basisklassen haben, eine ist ICombatantDataund die andere ICombatantLogic. Die beiden Implementierer von Daten sind einer für die in der Datenbank gespeicherten realen Objekte und der andere für meine Scheinobjekte.

Ich stoße jetzt auf Unsicherheiten bei der Gestaltung der logischen Seite der Dinge. Ich kann für jeden Spieler und jeden NPC einen Implementierer haben, aber dann habe ich ein Problem. Ein Kämpfer muss in der Lage sein, die von ihm verpackte Entität zurückzugeben. Sollte diese Getter-Methode Teil von Logik oder Daten sein? Ich bin der festen Überzeugung, dass es sich um Daten handeln sollte, da der logische Teil für die Ausführung von Kämpfen verwendet wird und nicht verfügbar ist, wenn jemand nur nach Informationen über einen bevorstehenden Kampf sucht. Die Datenklassen trennen jedoch nur Mock von DB, nicht Player von NPC. Wenn ich versuche, zwei untergeordnete Klassen des DB-Datenimplementierers zu haben, eine für jeden Entitätstyp, wie kann ich das dann erstellen, während ich meine Mocks in der Schleife halte? Benötige ich eine solche dritte Schnittstelle IEntityProvider, die ich in die Datenklassen einspeise?

Auch bei einigen der Ideen, über die ich nachgedacht habe, muss ich Kontrollen durchführen, um sicherzustellen, dass die Dinge nicht nicht übereinstimmen, z. B. dass die Logik für einen NPC versehentlich die Daten für einen Spieler verpackt. Macht das irgendeinen Sinn? Ist das eine Situation, die sogar möglich wäre, wenn die Architektur korrekt ist, oder würde das richtige Design dies vollständig verbieten, sodass ich nicht danach suchen muss?

Wenn mir jemand helfen könnte, nur ein Klassendiagramm oder etwas dafür zu entwerfen, würde es mir sehr helfen. Vielen Dank.

bearbeiten

Es ist auch nützlich zu beachten, dass die Scheindatenklasse das nicht wirklich benötigt Entity, da ich stattdessen alle Parameter wie Kampfstatistiken direkt angeben werde. Vielleicht wirkt sich das auf das richtige Design aus.

Tesserex
quelle
Meine Vermutung wird Combatant.entityim Kampf nicht verwendet und sollte daher nicht existieren. Vielleicht brauchen Sie eine andere Klasse, die EntityVsEntityCombatdie Kampflogik umschließt, Entity <--> CombatantZuordnungen enthält und EntityZustände nach Beendigung des Kampfes aktualisiert ? Vielleicht könnten weitere Informationen zu Ihrer aktuellen Architektur hilfreich sein.
Torious

Antworten:

1

Ein Teil der Art und Weise, wie ich dies in der Vergangenheit angegangen bin, besteht darin, keine völlig getrennten Darstellungen für Spieler und NPCs zu haben, während beide eine gemeinsame Schnittstelle implementieren müssen, um die Konvergenz der Darstellungen zwischen ihnen so weit wie möglich voranzutreiben indem Characterich sie nach einem gemeinsamen Modell klassifiziere, in das ich so viel über sie dränge, wie es sinnvoll ist, es zu verallgemeinern. Dies hilft, Probleme beim Ausführen von NPC-Operationen auf Spielern und dergleichen zu vermeiden, indem Operationen allgemeiner anwendbar gemacht werden, da die Darstellungen weniger natürlich voneinander abweichen als bei vollständig unabhängigen Implementierungen. Die grundlegende Nutzung des Polymorphismus hilft bei der Bewältigung der Fälle, die auseinander gehen müssen (zum Beispiel, wenn Sie Ihre gemacht habenCombatantLogicWenn Sie dafür verantwortlich sind, was passiert, wenn jemand stirbt, müssen Sie eine Überprüfung durchführen, um sicherzustellen, dass Sie die richtige Logik verwendet haben. Lassen Sie Spieler und NPCs also keine separaten, geeigneten die()Methoden implementieren .

Ich bin damit einverstanden, dass Ihr EntityTeil der Daten ist. Aufbauend auf dem, was ich gesagt habe, würde ich tatsächlich dazu tendieren, die Rolle von Ihnen zu entfernen oder einzuschränken CombatantData, damit die Kampflogik Werte direkt aus den Werten zieht Entity, möglicherweise CombatantDatanur mit der Speicherung teurer, kampfspezifisch berechneter Werte. Ihre Testmodelle würden sich dann mehr auf die Bereitstellung gefälschter EntityModelle als auf das Auffüllen konzentrieren CombatantData. (Wenn ich CombatantDataviele Informationen aus den Daten dupliziere, Entitystört mich das auf die gleiche Weise wie bei einer denormalisierten Datenbank. Wenn Sie jedoch an das Gesetz von Demeter glauben, das ich leidenschaftlich nicht tue, möchten Sie die Dinge nicht so tun, wie ich es tue Ich schlage vor. Wenn Sie an das Gesetz von Demeter glauben, bin ich mir natürlich nicht sicher, ob Sie es sindCombatantDatasollte sogar Zugang zum Entity.)

Chaos
quelle
CombatantData dupliziert Entitätsdaten nicht wirklich, sondern enthält den Status der Entität im Kampf, wie den aktuellen Zustand und etwaige Statuseffekte.
Tesserex
@ Tesserex: Ah, okay. Wenn dieser Zustand zwischen den Kämpfen nicht bestehen bleibt, ist das sinnvoll. Ignorieren Sie dann diesen Teil. :) Macht der Rest von dem, was ich sage, Sinn?
Chaos