Aqui está um requisito simplificado:
O usuário cria um
Question
com váriosAnswer
s.Question
deve ter pelo menos umAnswer
.Esclarecimento: pense
Question
eAnswer
como em um teste : há uma pergunta, mas várias respostas, onde poucas podem estar corretas. Usuário é o ator que está preparando este teste, portanto, ele cria perguntas e respostas.
Estou tentando modelar este exemplo simples para 1) corresponder ao modelo da vida real 2) para ser expressivo com o código, para minimizar possíveis usos indevidos e erros e dar dicas aos desenvolvedores sobre como usar o modelo.
Pergunta é uma entidade , enquanto resposta é objeto de valor . A pergunta contém respostas. Até agora, eu tenho essas soluções possíveis.
[A] fábrica dentroQuestion
Em vez de criar Answer
manualmente, podemos chamar:
Answer answer = question.createAnswer()
answer.setText("");
...
Isso criará uma resposta e a adicionará à pergunta. Em seguida, podemos manipular a resposta definindo suas propriedades. Dessa forma, apenas perguntas podem criar uma resposta. Além disso, evitamos ter uma resposta sem uma pergunta. No entanto, não temos controle sobre a criação de respostas, pois isso é codificado no Question
.
Há também um problema com o 'idioma' do código acima. Usuário é quem cria respostas, não a pergunta. Pessoalmente, não gosto de criar objetos de valor e, dependendo do desenvolvedor, preenchê-los com valores - como ele pode ter certeza do que é necessário adicionar?
[B] Fábrica dentro da pergunta, pegue a # 2
Alguns dizem que devemos ter esse tipo de método em Question
:
question.addAnswer(String answer, boolean correct, int level....);
Semelhante à solução acima, esse método utiliza dados obrigatórios para a resposta e cria um que também será adicionado à pergunta.
O problema aqui é que duplicamos o construtor do Answer
sem nenhuma boa razão. Além disso, a pergunta realmente cria uma resposta?
Dependências do construtor [C]
Sejamos livres para criar os dois objetos por nós mesmos. Vamos também expressar a dependência correta no construtor:
Question q = new Question(...);
Answer a = new Answer(q, ...); // answer can't exist without a question
Isso fornece dicas para o desenvolvedor, pois a resposta não pode ser criada sem uma pergunta. No entanto, não vemos o 'idioma' que diz que a resposta é 'adicionada' à pergunta. Por outro lado, precisamos mesmo vê-lo?
[D] Dependência de construtor, pegue # 2
Podemos fazer o oposto:
Answer a1 = new Answer("",...);
Answer a2 = new Answer("",...);
Question q = new Question("", a1, a2);
Esta é a situação oposta de cima. Aqui as respostas podem existir sem uma pergunta (que não faz sentido), mas a pergunta não pode existir sem resposta (que faz sentido). Além disso, a 'linguagem' aqui é mais clara sobre essa questão vai ter as respostas.
[E] maneira comum
Isto é o que chamo de maneira comum, a primeira coisa que as pessoas costumam fazer:
Question q = new Question("",...);
Answer a = new Answer("",...);
q.addAnswer(a);
que é a versão 'solta' das duas respostas acima, já que a resposta e a pergunta podem existir uma sem a outra. Não há nenhum indício especial que você tem para uni-los.
[F] Combinado
Ou devo combinar C, D, E - para cobrir todas as maneiras pelas quais o relacionamento pode ser feito, para ajudar os desenvolvedores a usar o que é melhor para eles.
Questão
Eu sei que as pessoas podem escolher uma das respostas acima com base no 'palpite'. Mas eu me pergunto se alguma das variantes acima é melhor que a outra com uma boa razão para isso. Além disso, não pense na pergunta acima. Gostaria de incluir aqui algumas práticas recomendadas que podem ser aplicadas na maioria dos casos - e, se você concordar, na maioria dos casos de uso de criação, algumas entidades são semelhantes. Além disso, vamos tornar a tecnologia independente aqui, por exemplo. Não quero pensar se o ORM será usado ou não. Só quero um modo expressivo e bom.
Alguma sabedoria nisso?
EDITAR
Ignore outras propriedades de Question
e Answer
, elas não são relevantes para a pergunta. Editei o texto acima e alterei a maioria dos construtores (onde necessário): agora eles aceitam qualquer um dos valores de propriedade necessários. Isso pode ser apenas uma sequência de perguntas ou um mapa de sequências em diferentes idiomas, status etc. - quaisquer que sejam as propriedades passadas, elas não são o foco disso;) Portanto, assuma que estamos acima de passar os parâmetros necessários, a menos que sejam diferentes. Thanx!
fonte
addAnswer
ouassignAnswer
seria uma linguagem melhor do que apenasanswer
, espero que você concorde com isso. De qualquer forma, minha pergunta é: você ainda escolheria o B e, por exemplo, teria a cópia da maioria dos argumentos no método de resposta? Isso não seria duplicação?Answer
é um objeto de valor, que será armazenado com uma raiz agregada de seu agregado. Você não armazena objetos de valor diretamente nem salva entidades se elas não forem raízes de seus agregados.Caso os requisitos sejam tão simples, que existam várias soluções possíveis, o princípio do KISS deve ser seguido. No seu caso, essa seria a opção E.
Há também o caso de criar código que expressa algo, que não deveria. Por exemplo, amarrando a criação das Respostas à Pergunta (A e B) ou fornecendo referência de Resposta à Pergunta (C e D), adicione um comportamento que não é necessário para o domínio e pode ser confuso. Além disso, no seu caso, a pergunta provavelmente seria agregada à resposta e a resposta seria um tipo de valor.
fonte
Eu iria [C] ou [E].
Primeiro, por que não A e B? Não quero que minha pergunta seja responsável por criar qualquer valor relacionado. Imagine se a pergunta tiver muitos outros objetos de valor - você colocaria um
create
método para cada um? Ou, se houver alguns agregados complexos, o mesmo caso.Por que não [D]? Porque é oposto ao que temos na natureza. Primeiro, criamos uma pergunta. Você pode imaginar uma página da Web onde você cria tudo isso - o usuário primeiro criaria uma pergunta, certo? Portanto, não D.
[E] é o KISS, como @Euphoric disse. Mas também começo a gostar de [C] recentemente. Isso não é tão confuso quanto parece. Além disso, imagine se a pergunta depende de mais coisas - então o desenvolvedor deve saber o que ele precisa colocar dentro da pergunta para que ela seja inicializada corretamente. Embora você esteja certo - não há linguagem 'visual' explicando que a resposta é realmente adicionada à pergunta.
Leitura adicional
Perguntas como essa me fazem pensar se nossas linguagens de computador são muito genéricas para modelagem. (Entendo que eles precisam ser genéricos para responder a todos os requisitos de programação). Recentemente, estou tentando encontrar uma maneira melhor de expressar a linguagem comercial usando interfaces fluentes. Algo parecido com isto (na linguagem sudo):
ou seja, tentando se afastar de qualquer classe * Services e * Repository grande para pedaços menores da lógica de negócios. Apenas uma ideia.
fonte
Acredito que você perdeu um ponto aqui, sua raiz agregada deve ser sua entidade de teste.
E se realmente for o caso, acredito que um TestFactory seria o mais adequado para responder ao seu problema.
Você delegaria o edifício de perguntas e respostas à fábrica e, portanto, poderia usar basicamente qualquer solução que pensasse sem danificar seu modelo, porque está ocultando o cliente da maneira como instancia suas subentidades.
Isto é, desde que o TestFactory seja a única interface usada para instanciar seu teste.
fonte