🇧🇷 Guia para modelagem de domínios ricos

Vou iniciar esse artigo com um exemplo de classe e fazer a pergunta: Você acha que o código abaixo é um bom domain model ?

Obs.: Não há nada de errado em usar classes assim quando não há complexidade de negócio, mas você tem que ter em mente que isso não é um domain model. Isso é mais parecido com um data transfer object (DTO).

Faz um tempo que eu vejo implementações de “domain models” da maneira demonstrada acima e toda lógica de manipulação dessas classes é colocada em outro lugar, muitas vezes chamado de “XyzService”, no nosso exemplo “OrderService”:

Ambos exemplos mostram o que se chama de modelos de domínio anêmico, ou em inglês anemic domain model. Assunto muito bem argumentado por Marin Fowler. Também de acordo com ele, um modelo de domínio é um modelo de objeto do domínio que incorpora comportamento e dados.

Se refatorarmos o código e colocarmos comportamento e dados na mesma classe, o modelo Order se torna mais claro e mostra o seu objetivo:

Agora parece melhor.

Mas agora, o que aconteceria ao construir a classe e adicionar um item ao pedido ?

BOOM! Null Reference Exception, porque o nosso modelo de domínio ainda precisa de um gerenciamento de estado e a lista de itens está nula.

O objeto deve encapsular a maneira que ele é construído, modificado e se manter em um estado válido.

Vamos modificar a classe com private setters e construtores privados, evitando que algum código externo construa/altere o objeto em um estado inválido.

Precisamos de uma maneira de criar o pedido. Vamos adicionar um método que é capaz de criar um pedido em um estado válido:

O mesmo para a classe OrderItem:

Se a classe Order for consumida por um código externo, a única opção que é exposta para criá-la é usando o método “New”. Não será possível alterar o estado em um código externo, pois suas propriedades são somente leitura do ponto de vista externo.

É possível notar que a nossa classe Order tem uma propriedade que armazena uma lista de itens de um pedido e um método chamado AddItem() usado para adicionar itens validos ao pedido. Mesmo assim, um código externo pode acessar a propriedade de lista e adicionar um item sem validação, uma vez que o objeto List do framework é mutável.

Uma maneira de solucionar essa questão é sempre expor uma cópia imutável dos itens e encapsular a lista original:

Com essa alteração, a entidade pode modificar a lista e códigos externos podem ver a lista sem modificá-la.

Aplicando esses passos, temos uma classe completamente independente, incorruptível e auto gerenciável.

Para ver o resultado final das classes, acesse o gist.

Este artigo também está disponível em Inglês.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store