Eu gostaria de escrever um aplicativo parecido com comércio eletrônico.
E você sabe que em aplicativos semelhantes, os produtos podem ter propriedades e recursos diferentes. Para simular essa oportunidade, criei as seguintes entidades de modelo de domínio:
Categoria - é algo como "eletrônicos> computadores", ou seja, tipos de produtos. As categorias contêm uma lista de propriedades (Lista <Propriedade>).
Entidade independente da propriedade que contém o nome, unidades de medida, tipo de dados. Por exemplo "nome", "peso", "tamanho da tela". A mesma propriedade pode ter produtos diferentes.
Produto - contém apenas o nome e a lista de valores relacionados às propriedades. Valor é um objeto que contém apenas o campo de valor e a identificação do campo da propriedade.
Decidi originalmente tornar a categoria como agregada única nesse esquema, porque, por exemplo, quando adiciono um novo produto, preciso conhecer todos os dados relacionados à categoria atual, incluindo propriedades relacionadas à categoria atual ( category.AddNewProduct (product) ). Mas o que devo fazer quando só precisar adicionar uma nova propriedade que não pertença a nenhuma categoria. Por exemplo, não posso fazer esta categoria. AddNewProperty (propriedade) porque diz claramente que adicionamos a propriedade a uma categoria específica.
Ok, no próximo passo eu decidi separar Property em um agregado separado, mas então será uma lista com entidades simples.
É claro que posso criar algo como PropertyAggregate para manter uma lista interna de propriedades e regras de negócios, mas quando adiciono um produto, preciso ter dentro da categoria a lista inteira de propriedades pertencentes a essa categoria para verificar os invariantes. Mas também estou ciente de que manter os links dentro do agregado em outros agregados é uma prática ruim.
Quais são as opções para projetar esse caso de negócios?
fonte
Respostas:
Na perspectiva DDD,
Category
,Product
eProperty
são entidades: todos eles correspondem a objetos que têm sua própria identidade.Opção 1: seu design original
Você criou
Category
a raiz de um único agregado. De um lado, isso faz sentido, porque o agregado assegura a coerência quando seus objetos são modificados, eProduct
deve ter aProperties
de seuCategory
:Mas, por outro lado, o agregado único significa que todos os seus objetos estão relacionados a uma raiz que os possui e todas as referências externas devem ser feitas através dessa raiz agregada. Isso implica que:
Product
pertence a um e apenas umCategory
. Se oCategory
é excluído, também o éProducts
.Property
pertence a um e apenas umCategory
. Caso contrário, se "telas de TV" e "monitores de computador" tiverem duas categorias, "telas de TV: tamanho" e "monitores de computador: tamanho" seriam duas propriedades diferentes.O segundo ponto não corresponde à sua narrativa: " Mas o que devo fazer quando só preciso adicionar um novo
Property
que não pertença a nenhuma categoria ". E não está claro se o mesmoProperties
pode ser usado em diferentesCategories
.Opção 2: Propriedade fora do agregado
Se um
Property
existir independentemente doCategories
, ele deve estar fora do agregado. E o mesmo se você quiser compartilharProperties
entreCategories
(o que faz sentido para altura, largura, tamanhos, etc ...). Este parece definitivamente ser o caso.A conseqüência está no link entre
Property
e as coisas que pertencem ao agregado: enquanto você pode navegar do interior do agregado paraProperty
, não é mais permitido ir diretamente de aProperty
para os valores correspondentes. Essa restrição de navegabilidade pode ser mostrada em um diagrama UML:Observe que esse design não impede que você
List<Property>
entreCategory
, com uma semântica de referência (por exemplo, java): cada referência na lista se refere a umProperty
objeto compartilhável em um repositório.O único problema com esse design é que você pode alterá-
Property
lo ou excluí-lo: como está fora do agregado, o agregado não pode cuidar da consistência de seus invariantes. Mas isso não é um problema. É a conseqüência dos princípios DDD e da complexidade do mundo real. Aqui está uma citação de Eric Evans em seu livro seminal " Design Orientado a Domínio: Enfrentando a Complexidade no Coração do Software ":Portanto, sim, se você alterar a
Property
, precisará garantir que um serviço verifique as categorias referentes a ele seja atualizado conforme necessário.Opção 3: Categoria, Propriedade e Produto em diferentes agregados
Eu apenas me pergunto se a suposição de que a
Product
pertence a um singleCategory
é fundada:Product
em váriasCategories
. Por exemplo, você encontrará "Laptop Marca X Modelo Y" na categoria "Laptops" e na categoria "Computadores" e uma "impressora multifuncional Z" na categoria "impressora", "scanner" e "fax".Product
primeiro e só depois o atribua a Categorias e preencha os valores?Não simplificará as agregações, e você terá ainda mais regras que abrangem agregações. Mas seu sistema seria muito mais à prova de futuro.
fonte
Property
ultrapassar os limites doCategory
agregado, isso significa que eleProperty
se torna agregado e precisa de um repositório? Se for verdade, como passar o requisitoList<Property>
para aCategory
instância? Através do construtor? Vai dar certo? E como faço para descobrir a lista deProperty
IDs de umCategory
que ainda não foi criado?Feature
e ela pertencerá apenas aoProduct
. e essa entidade não participará da pesquisa. O que você disse ?A meu ver, você pode resolver isso de duas maneiras:
Categoria é um tipo especial de produto
Isso significa que, para qualquer produto em seu banco de dados, ele contém uma chave estrangeira apontando para o mesmo produto da tabela. Um produto é um produto apenas se não existirem produtos cuja chave estrangeira seja igual à identificação do referido produto. Em outras palavras, se ele não possui produtos, é um produto.
Isso simplificaria um pouco as coisas. Os produtos para propriedades teriam um relacionamento um para muitos e, portanto, suas categorias também terão um relacionamento para muitos, pois também são produtos. Adicionar uma propriedade a uma categoria seria tão fácil quanto adicionar uma propriedade a um produto no seu programa. Carregar todas as propriedades significaria combinar as propriedades do produto com as propriedades do produto de categoria associado e até chegar a um produto de categoria sem pai.
Seu aplicativo de comércio eletrônico precisaria fazer essa distinção, mas se você provavelmente carregar produtos de uma categoria de qualquer maneira, não será uma perda de desempenho saber se você está lidando com uma categoria ou um produto. Também se presta a pesquisar na forma de árvores ao nível do produto, pois cada produto (categoria) abriria uma lista de subprodutos sem muito trabalho adicional.
A desvantagem disso é, obviamente, as informações extras presentes no produto que não fazem sentido para uma categoria criariam campos não utilizados no produto. Embora essa solução seja mais flexível em seu aplicativo, também é um pouco menos intuitiva.
Relacionamento muitos-para-muitos
Os produtos não estão mais em um relacionamento composto com a propriedade. Você cria uma tabela ProductProperty com chaves estrangeiras da tabela do produto e da tabela de propriedades que vinculam as duas. Da mesma forma, você tem uma tabela de categorias com um relacionamento muitos para muitos com a tabela de propriedades e uma tabela CategoryProperty com chaves estrangeiras da tabela de categorias e da tabela de propriedades.
O produto em si teria um relacionamento muitos-para-um com a categoria, permitindo que você crie essencialmente uma lista de propriedades exclusivas pertencentes ao produto e à categoria por meio de uma instrução de seleção bem formalizada.
Do ponto de vista do banco de dados, isso é definitivamente mais limpo e mais flexível. Provavelmente, seu aplicativo pode funcionar sem a necessidade de lidar diretamente com CategoryProperty ou ProductProperty se a consulta for feita corretamente. No entanto, você também não deve tratar a categoria ou o produto como proprietário da propriedade. Deve ser sua própria entidade dentro do seu programa. Isso também significa que o gerenciamento das referidas propriedades seria uma questão de criar a própria propriedade e associá-la a uma categoria ou produto em duas etapas separadas. Certamente mais trabalho que a primeira solução, mas de nenhuma maneira mais difícil.
Além disso, você também teria que executar uma verificação adicional ao excluir a categoria ou o produto se alguma de suas propriedades estiver sendo usada por outras pessoas (diferente da primeira solução em que você pode eliminar com segurança todas as propriedades associadas de um determinado produto / categoria) .
Conclusão
Em um contexto profissional, eu iria além da categoria de milhas e distâncias entre produtos e produtos e propriedades, usando a abordagem muitos para muitos. Não haveria possibilidade de sobreposição de dados e, em certo sentido, é mais fácil raciocinar cada um desses três como sua própria entidade. No entanto, de maneira alguma a primeira solução é ruim, pois também permite que você escreva um aplicativo mais simples. Apenas saiba que, se você pensou que poderia eventualmente mudar de uma solução para outra, provavelmente seria do seu interesse escolher a segunda.
Boa sorte!
fonte