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 ICombatantData
und 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.
quelle
Combatant.entity
im Kampf nicht verwendet und sollte daher nicht existieren. Vielleicht brauchen Sie eine andere Klasse, dieEntityVsEntityCombat
die Kampflogik umschließt,Entity <--> Combatant
Zuordnungen enthält undEntity
Zustände nach Beendigung des Kampfes aktualisiert ? Vielleicht könnten weitere Informationen zu Ihrer aktuellen Architektur hilfreich sein.Antworten:
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
Character
ich 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 habenCombatantLogic
Wenn 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, geeignetendie()
Methoden implementieren .Ich bin damit einverstanden, dass Ihr
Entity
Teil 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änkenCombatantData
, damit die Kampflogik Werte direkt aus den Werten ziehtEntity
, möglicherweiseCombatantData
nur mit der Speicherung teurer, kampfspezifisch berechneter Werte. Ihre Testmodelle würden sich dann mehr auf die Bereitstellung gefälschterEntity
Modelle als auf das Auffüllen konzentrierenCombatantData
. (Wenn ichCombatantData
viele Informationen aus den Daten dupliziere,Entity
stö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 sindCombatantData
sollte sogar Zugang zumEntity
.)quelle