Hier ist eine vereinfachte Anforderung:
Benutzer erstellt ein
Question
mit mehrerenAnswer
s.Question
muss mindestens eine habenAnswer
.Klarstellung: Denken Sie
Question
undAnswer
wie in einem Test : Es gibt eine Frage, aber mehrere Antworten, bei denen nur wenige richtig sein können. Der Benutzer ist der Schauspieler, der diesen Test vorbereitet, daher erstellt er Fragen und Antworten.
Ich versuche, dieses einfache Beispiel so zu modellieren, dass 1) es mit dem realen Modell übereinstimmt 2) mit dem Code ausdrucksstark ist, um potenziellen Missbrauch und Fehler zu minimieren und Entwicklern Hinweise zur Verwendung des Modells zu geben.
Frage ist eine Entität , während Antwort Wertobjekt ist . Frage enthält Antworten. Bisher habe ich diese möglichen Lösungen.
[A] Fabrik im InnerenQuestion
Anstatt Answer
manuell zu erstellen , können wir Folgendes aufrufen:
Answer answer = question.createAnswer()
answer.setText("");
...
Dadurch wird eine Antwort erstellt und der Frage hinzugefügt. Dann können wir die Antwort manipulieren, indem wir ihre Eigenschaften festlegen. Auf diese Weise können nur Fragen eine Antwort liefern. Wir verhindern auch, dass wir eine Antwort ohne Frage haben. Wir haben jedoch keine Kontrolle über das Erstellen von Antworten, da dies in der Question
.
Es gibt auch ein Problem mit der 'Sprache' des obigen Codes. Der Benutzer ist derjenige, der Antworten erstellt, nicht die Frage. Persönlich mag ich es nicht, wenn wir ein Wertobjekt erstellen und es je nach Entwickler mit Werten füllen - wie kann er sicher sein, was hinzugefügt werden muss?
[B] Fabrik in Frage, nimm # 2
Einige sagen, wir sollten diese Art von Methode haben in Question
:
question.addAnswer(String answer, boolean correct, int level....);
Ähnlich wie bei der obigen Lösung verwendet diese Methode obligatorische Daten für die Antwort und erstellt eine, die ebenfalls zur Frage hinzugefügt wird.
Das Problem hierbei ist, dass wir den Konstruktor von ohne guten Grund duplizierenAnswer
. Schafft die Frage wirklich eine Antwort?
[C] Konstruktorabhängigkeiten
Lassen Sie uns beide Objekte selbst erstellen. Lassen Sie uns auch das Abhängigkeitsrecht im Konstruktor ausdrücken:
Question q = new Question(...);
Answer a = new Answer(q, ...); // answer can't exist without a question
Dies gibt dem Entwickler Hinweise, da die Antwort nicht ohne Frage erstellt werden kann. Wir sehen jedoch nicht die "Sprache", die besagt, dass die Antwort der Frage "hinzugefügt" wird. Müssen wir es auf der anderen Seite wirklich sehen?
[D] Konstruktorabhängigkeit, nimm # 2
Wir können das Gegenteil tun:
Answer a1 = new Answer("",...);
Answer a2 = new Answer("",...);
Question q = new Question("", a1, a2);
Dies ist die entgegengesetzte Situation von oben. Hier können Antworten ohne eine Frage existieren (was keinen Sinn ergibt), aber eine Frage kann nicht ohne Antwort existieren (was keinen Sinn ergibt). Auch die ‚Sprache‘ ist hier deutlicher zu dieser Frage wird hat die Antworten.
[E] Gemeinsamer Weg
Dies ist, was ich den üblichen Weg nenne, das erste, was Menschen normalerweise tun:
Question q = new Question("",...);
Answer a = new Answer("",...);
q.addAnswer(a);
Dies ist eine "lose" Version der beiden oben genannten Antworten, da sowohl Antwort als auch Frage ohne einander existieren können. Es gibt keinen besonderen Hinweis , dass Sie haben sie zusammen zu binden.
[F] Kombiniert
Oder sollte ich C, D, E kombinieren, um alle Möglichkeiten der Beziehungsherstellung abzudecken und Entwicklern zu helfen, das zu verwenden, was für sie am besten ist.
Frage
Ich weiß, dass die Leute eine der oben genannten Antworten basierend auf der Vermutung auswählen können. Aber ich frage mich, ob eine der oben genannten Varianten besser ist als die andere, mit einem guten Grund dafür. Denken Sie auch nicht an die obige Frage. Ich möchte hier einige Best Practices zusammenfassen, die in den meisten Fällen angewendet werden können. Wenn Sie zustimmen, sind die meisten Anwendungsfälle bei der Erstellung einiger Entitäten ähnlich. Lassen Sie uns hier auch technologieunabhängig sein, z. Ich möchte nicht darüber nachdenken, ob ORM verwendet wird oder nicht. Ich will nur einen guten, ausdrucksstarken Modus.
Irgendeine Weisheit dazu?
BEARBEITEN
Bitte ignorieren Sie andere Eigenschaften von Question
und Answer
, sie sind für die Frage nicht relevant. Ich habe den obigen Text bearbeitet und die meisten Konstruktoren geändert (wo erforderlich): Jetzt akzeptieren sie alle erforderlichen Eigenschaftswerte. Dies kann nur eine Fragezeichenfolge oder eine Zuordnung von Zeichenfolgen in verschiedenen Sprachen, Status usw. sein. Unabhängig davon, welche Eigenschaften übergeben werden, stehen sie nicht im Mittelpunkt.) Nehmen wir also an, wir übersteigen die erforderlichen Parameter, sofern nicht anders angegeben. Danke!
quelle
addAnswer
oderassignAnswer
wäre eine bessere Sprache als nuranswer
, ich hoffe, Sie stimmen dem zu. Wie auch immer, meine Frage ist - würden Sie sich immer noch für das B entscheiden und z. B. die Kopie der meisten Argumente in der Antwortmethode haben? Wäre das nicht eine Vervielfältigung?Answer
ist ein Wertobjekt, das mit einer aggregierten Wurzel seines Aggregats gespeichert wird. Sie speichern Wertobjekte weder direkt noch speichern Sie Entitäten, wenn sie keine Wurzeln ihrer Aggregate sind.Wenn die Anforderungen so einfach sind, dass mehrere mögliche Lösungen existieren, sollte das KISS-Prinzip befolgt werden. In Ihrem Fall wäre das Option E.
Es gibt auch Fälle, in denen Code erstellt wird, der etwas ausdrückt, was nicht der Fall sein sollte. Wenn Sie beispielsweise die Erstellung von Antworten auf Frage (A und B) verknüpfen oder einen Antwortverweis auf Frage (C und D) geben, fügen Sie ein Verhalten hinzu, das für die Domäne nicht erforderlich und möglicherweise verwirrend ist. In Ihrem Fall würde die Frage höchstwahrscheinlich mit Antwort aggregiert, und Antwort wäre ein Werttyp.
quelle
Ich würde entweder [C] oder [E] gehen.
Erstens, warum nicht A und B? Ich möchte nicht, dass meine Frage für die Schaffung eines verwandten Werts verantwortlich ist. Stellen Sie sich vor, Frage hat viele andere Wertobjekte - würden Sie
create
für jedes eine Methode setzen ? Oder wenn es einige komplexe Aggregate gibt, der gleiche Fall.Warum nicht [D]? Weil es dem entgegengesetzt ist, was wir in der Natur haben. Wir erstellen zuerst eine Frage. Sie können sich eine Webseite vorstellen, auf der Sie all dies erstellen - der Benutzer würde zuerst eine Frage erstellen, oder? Daher nicht D.
[E] ist KISS, wie @Euphoric sagte. Aber ich fange in letzter Zeit auch an, [C] zu mögen. Das ist nicht so verwirrend, wie es scheint. Stellen Sie sich außerdem vor, wenn die Frage von mehr Dingen abhängt, muss der Entwickler wissen, was er in die Frage einfügen muss, damit sie ordnungsgemäß initialisiert wird. Obwohl Sie Recht haben, gibt es keine "visuelle" Sprache, die erklärt, dass die Antwort tatsächlich zur Frage hinzugefügt wird.
Zusätzliche Lektüre
Bei solchen Fragen frage ich mich, ob unsere Computersprachen für die Modellierung zu allgemein sind. (Ich verstehe, dass sie generisch sein müssen, um alle Programmieranforderungen zu erfüllen). Kürzlich habe ich versucht, einen besseren Weg zu finden, um die Geschäftssprache über fließende Schnittstellen auszudrücken. So etwas (in Sudo-Sprache):
dh versuchen, von großen * Services- und * Repository-Klassen zu kleineren Teilen der Geschäftslogik überzugehen. Nur eine Idee.
quelle
Ich glaube, Sie haben hier einen Punkt verpasst. Ihre aggregierte Wurzel sollte Ihre Testeinheit sein.
Und wenn es wirklich so ist, ist eine TestFactory meiner Meinung nach am besten geeignet, um Ihr Problem zu beantworten.
Sie würden das Frage-und-Antwort-Gebäude an die Factory delegieren und könnten daher grundsätzlich jede Lösung verwenden, an die Sie gedacht haben, ohne Ihr Modell zu beschädigen, da Sie sich vor dem Client verstecken, wie Sie Ihre Unterentitäten instanziieren.
Dies gilt, solange die TestFactory die einzige Schnittstelle ist, über die Sie Ihren Test instanziieren.
quelle