Voici une exigence simplifiée:
L'utilisateur crée un
Question
avec plusieursAnswer
s.Question
doit en avoir au moins unAnswer
.Clarification: pensez
Question
etAnswer
comme dans un test : il y a une question, mais plusieurs réponses, où peu peuvent être correctes. L'utilisateur est l'acteur qui prépare ce test, il crée donc des questions et des réponses.
J'essaie de modéliser cet exemple simple pour 1) correspondre au modèle de la vie réelle 2) pour être expressif avec le code, afin de minimiser les abus et les erreurs potentiels, et de donner des conseils aux développeurs sur la façon d'utiliser le modèle.
La question est une entité , tandis que la réponse est un objet de valeur . La question contient des réponses. Jusqu'à présent, j'ai ces solutions possibles.
[A] Usine à l'intérieurQuestion
Au lieu de créer Answer
manuellement, nous pouvons appeler:
Answer answer = question.createAnswer()
answer.setText("");
...
Cela va créer une réponse et l' ajouter à la question. Ensuite, nous pouvons manipuler la réponse en définissant ses propriétés. De cette façon, seules les questions peuvent créer une réponse. De plus, nous empêchons d'avoir une réponse sans question. Pourtant, nous n'avons aucun contrôle sur la création de réponses, car cela est codé en dur dans le Question
.
Il y a aussi un problème avec la «langue» du code ci-dessus. L'utilisateur est celui qui crée les réponses, pas la question. Personnellement, je n'aime pas que nous créons un objet de valeur et en fonction du développeur pour le remplir de valeurs - comment peut-il être sûr de ce qu'il faut ajouter?
[B] Usine à l'intérieur de la question, prenez # 2
Certains disent que nous devrions avoir ce genre de méthode dans Question
:
question.addAnswer(String answer, boolean correct, int level....);
Semblable à la solution ci-dessus, cette méthode prend des données obligatoires pour la réponse et en crée une qui sera également ajoutée à la question.
Le problème ici est que nous dupliquons le constructeur de la Answer
sans raison valable. De plus, la question crée-t-elle vraiment une réponse?
[C] Dépendances du constructeur
Soyons libres de créer les deux objets par nous-mêmes. Exprimons également le droit de dépendance dans le constructeur:
Question q = new Question(...);
Answer a = new Answer(q, ...); // answer can't exist without a question
Cela donne des conseils au développeur, car la réponse ne peut pas être créée sans une question. Cependant, nous ne voyons pas la «langue» qui dit que la réponse est «ajoutée» à la question. D'un autre côté, avons-nous vraiment besoin de le voir?
[D] Dépendance constructeur, prendre # 2
On peut faire le contraire:
Answer a1 = new Answer("",...);
Answer a2 = new Answer("",...);
Question q = new Question("", a1, a2);
C'est la situation inverse de ci-dessus. Ici, les réponses peuvent exister sans question (ce qui n'a pas de sens), mais la question ne peut exister sans réponse (qui a du sens). En outre, la « langue » est ici plus clair sur cette question sera avoir les réponses.
[E] Voie commune
C'est ce que j'appelle la voie commune, la première chose que ppl fait habituellement:
Question q = new Question("",...);
Answer a = new Answer("",...);
q.addAnswer(a);
qui est une version «lâche» des deux réponses ci-dessus, car la réponse et la question peuvent exister l'une sans l'autre. Il n'y a aucune indication particulière que vous devez les lier ensemble.
[F] Combiné
Ou devrais-je combiner C, D, E - pour couvrir toutes les façons dont la relation peut être établie, afin d'aider les développeurs à utiliser ce qui leur convient le mieux.
Question
Je sais que les gens peuvent choisir l'une des réponses ci-dessus en fonction du «pressentiment». Mais je me demande si l'une des variantes ci-dessus est meilleure que l'autre avec une bonne raison à cela. De plus, s'il vous plaît ne pensez pas à l'intérieur de la question ci-dessus, je voudrais présenter ici certaines des meilleures pratiques qui pourraient être appliquées à la plupart des cas - et si vous êtes d'accord, la plupart des cas d'utilisation de la création de certaines entités sont similaires. En outre, laisse la technologie agnostique ici, par exemple. Je ne veux pas penser si l'ORM va être utilisé ou non. Je veux juste un bon mode expressif.
Une sagesse à ce sujet?
ÉDITER
Veuillez ignorer les autres propriétés de Question
et Answer
, elles ne sont pas pertinentes pour la question. J'ai édité le texte ci-dessus et changé la plupart des constructeurs (si nécessaire): maintenant ils acceptent toutes les valeurs de propriété nécessaires. Cela peut être juste une chaîne de questions, ou une carte de chaînes dans différentes langues, statuts, etc. - quelles que soient les propriétés transmises, elles ne sont pas un objectif pour cela;) Supposons donc simplement que nous dépassons les paramètres nécessaires, sauf indication contraire. Merci!
addAnswer
ouassignAnswer
serait un meilleur langage que justeanswer
, j'espère que vous êtes d'accord là-dessus. Quoi qu'il en soit, ma question est - iriez-vous toujours pour le B et par exemple avoir la copie de la plupart des arguments dans la méthode de réponse? Ne s'agirait-il pas d'une duplication?Answer
est un objet de valeur, il va être stocké avec une racine agrégée de son agrégat. Vous ne stockez pas directement les objets de valeur, et vous n'enregistrez pas d'entités si elles ne sont pas des racines de leurs agrégats.Dans le cas où les exigences sont si simples, qu'il existe plusieurs solutions possibles, le principe KISS doit être suivi. Dans votre cas, ce serait l'option E.
Il y a aussi le cas de créer du code qui exprime quelque chose, qu'il ne devrait pas. Par exemple, lier la création de réponses à la question (A et B) ou donner une référence de réponse à la question (C et D) ajoute un comportement qui n'est pas nécessaire au domaine et peut être déroutant. De plus, dans votre cas, la question serait très probablement agrégée avec la réponse et la réponse serait un type de valeur.
la source
J'irais soit [C] ou [E].
D'abord, pourquoi pas A et B? Je ne veux pas que ma question soit responsable de la création d'une valeur associée. Imaginez si Question a beaucoup d'autres objets de valeur - mettriez-vous la
create
méthode pour chacun? Ou s'il existe des agrégats complexes, le même cas.Pourquoi pas [D]? Parce que c'est contraire à ce que nous avons dans la nature. Nous créons d'abord une question. Vous pouvez imaginer une page Web où vous créez tout cela - l'utilisateur créerait d'abord une question, non? Par conséquent, pas D.
[E] est KISS, comme l'a dit @Euphoric. Mais je commence aussi à aimer [C] récemment. Ce n'est pas aussi déroutant qu'il n'y paraît. De plus, imaginez si la question dépend de plus de choses - alors le développeur doit savoir ce qu'il doit mettre à l'intérieur de la question pour l'initialiser correctement. Bien que vous ayez raison - il n'y a pas de langage «visuel» expliquant que la réponse est réellement ajoutée à la question.
Lecture complémentaire
Des questions comme celle-ci me font me demander si nos langages informatiques sont trop génériques pour la modélisation. (Je comprends qu'ils doivent être génériques pour répondre à toutes les exigences de programmation). Récemment, j'essaie de trouver une meilleure façon d'exprimer le langage des affaires en utilisant des interfaces fluides. Quelque chose comme ça (en langue sudo):
c'est-à-dire essayer de s'éloigner de n'importe quel gros * Services et * classes de référentiel vers de plus petits morceaux de logique métier. Juste une idée.
la source
Je crois que vous avez raté un point ici, votre racine agrégée devrait être votre entité de test.
Et si c'est vraiment le cas, je pense qu'une TestFactory serait la mieux adaptée pour répondre à votre problème.
Vous délégueriez le bâtiment des questions et réponses à la fabrique et, par conséquent, vous pourriez essentiellement utiliser n'importe quelle solution à laquelle vous pensiez sans corrompre votre modèle, car vous cachez au client la façon dont vous instanciez vos sous-entités.
C'est, tant que la TestFactory est la seule interface que vous utilisez pour instancier votre test.
la source