Um dos benefícios das classes de domínio ricas é que você pode chamar seu comportamento (métodos) sempre que tiver a referência ao objeto em qualquer camada. Além disso, você tende a escrever métodos pequenos e distribuídos que colaboram juntos. Em classes de domínio anêmicas, você tende a escrever métodos processuais gordos (na camada de serviço) que geralmente são orientados pelo caso de uso. Eles geralmente são menos fáceis de manter em comparação com as classes de domínio avançadas.
Um exemplo de classes de domínio com comportamentos:
class Order {
String number
List<OrderItem> items
ItemList bonus
Delivery delivery
void addItem(Item item) { // add bonus if necessary }
ItemList needToDeliver() { // items + bonus }
void deliver() {
delivery = new Delivery()
delivery.items = needToDeliver()
}
}
O método needToDeliver()
retornará uma lista de itens que precisam ser entregues, incluindo bônus. Ele pode ser chamado dentro da classe, de outra classe relacionada ou de outra camada. Por exemplo, se você passar Order
para visualizar, poderá usar needToDeliver()
de selecionado Order
para exibir a lista de itens a serem confirmados pelo usuário antes de clicar no botão Salvar para persistir o Order
.
Respondendo a um comentário
É assim que eu uso a classe de domínio do controlador:
def save = {
Order order = new Order()
order.addItem(new Item())
order.addItem(new Item())
repository.create(order)
}
A criação de Order
e LineItem
é em uma transação. Se um dos LineItem
não puder ser criado, nenhum Order
será criado.
Costumo ter métodos que representam uma única transação, como:
def deliver = {
Order order = repository.findOrderByNumber('ORDER-1')
order.deliver()
// save order if necessary
}
Qualquer coisa dentro deliver()
será executada como uma única transação. Se eu precisar executar muitos métodos não relacionados em uma única transação, criaria uma classe de serviço.
Para evitar a exceção de carregamento lento, eu uso o gráfico de entidade nomeada JPA 2.1. Por exemplo, no controlador para tela de entrega, posso criar um método para carregar o delivery
atributo e ignorar bonus
, como repository.findOrderByNumberFetchDelivery()
. Na tela de bônus, chamo outro método que carrega o bonus
atributo e ignoro delivery
, como repository.findOrderByNumberFetchBonus()
. Isso requer disciplina, pois ainda não consigo ligar deliver()
para a tela de bônus.