domingo, 6 de setembro de 2015

Ciclo de vida - DDD


Todos os objetos têm um ciclo de vida, alguns têm vida longa, passando por vários estados e sendo persistidos para posterior utilização, outros têm a vida mais curta sendo apenas utilizados em memória, alguns são criados apenas com uma simples chamada em seu construtor, outros exigem mais processamento para serem criados. Controlar estes objetos implica em 2 desafios para um Design Dirigido por Modelos, manter a integridade do objeto durante todo o ciclo de vida e impedir que o modelo se deixe levar pela complexidade do gerenciamento do ciclo de vida. Para tratar destas questões utilizaremos os padrões Agradado, Fábrica e Repositório.

Agregado

Em um sistema de cadastro temos um objeto pessoa que tem os atributos nome, telefone, data de nascimento e endereço que é uma referencia a outro objeto, este objeto pessoa precisa ser excluído. Seus atributos pertencem apenas a ele e podem ser excluídos sem problema, mas pode haver outras pessoas fazendo uso deste mesmo endereço. Se o endereço for apagado perderemos dados dos objetos que fazem referencia ao endereço e se deixarmos correremos o risco de termos endereços inutilizados. Como saber onde um objeto formado por outros objetos começa e termina? Para uma resposta adequada para está pergunta mais uma vez é necessário um conhecimento aprofundado do domínio, desta vez entendendo a frequência de alteração entre as instâncias de uma classe.

Um agregado é um conjunto de objetos associados que são tratados como uma unidade para fins de alterações de dados.

Cada agregado possui um limite e uma raiz. O limite define o que está dentro do agregado, a raiz é uma entidade única do agregado.

Dentro de um agregado os objetos internos podem fazer referencias uns aos outros, mas objetos externos tem acesso apenas à raiz. Somente raízes podem ser obtidas diretamente de bancos de dados, se um objeto externo precisa de uma entidade ou objeto de valor que esta dentro de um agregado, este deve pedir a raiz, que ira fornecê-lo.

Uma operação de exclusão deve remover todos os objetos que estão dentro dos limites do agregado, como não há nenhuma referencia externa, fica fácil remover todos os objetos do agregado.

Quando é feita uma alteração em algum objeto do agregado, todas as invariantes do agregado inteiro devem ser satisfeitas. Invariantes são regras de consistência que devem ser mantidas sempre que houver alteração em membro do agregado.

Evans (Evans, 2004) define a função de um agregado como:

Agrupe as ENTIDADES e os OBJETOS DE VALOR em AGREGADOS e define os limites em torno de cada um. Escolha uma ENTIDADE para ser a raiz de cada AGREGADO e controle todo o acesso aos objetos dentro do limite através da raiz. Permita que objetos externos façam referencia somente à raiz. Referencias transitórias a membros internos podem ser transmitidas para isso dentro de apenas uma única operação. Como a raiz controla o acesso, ela não pode ser surpreendida com alterações na parte interna. Esse arranjo torna prática a execução de todas as invariantes dos objetos no AGREGADO e para o AGREGADO como um todo em qualquer alteração de estado.

Fábricas

São classes responsáveis pela criação de objetos, algumas vezes a criação de um agregado ou outro objeto é tão complexa que não queremos manter o código de criação deste objeto na classe que o compõe, então colocarmos toda as regras de criação em uma fábrica. Uma fábrica encapsula o conhecimento necessário para criar objeto complexo ou agregado.

Existem diversos designs de fábrica, cada uma para diferentes fins, factory method, abstract factory e builder, não esta no escopo deste trabalho descrever como implementar cada tipo, vamos especificar onde podemos utilizar a fábrica para manter o Design Dirigido por Modelos.


Uma fábrica tem que satisfazer duas exigências:

Uma fábrica deve gerar um objeto em um estado consistente, ou seja, todas as

suas invariantes devem ter sido satisfeitas para entidades, para objetos de valor seus atributos devem está no estado final correto.

Fábricas devem ter uma interface abstrata.

Seguindo essas exigências onde devemos colocar as fábricas dentro do nosso modelo de domínio? Se precisarmos criar um objeto de um agregado já existente, podemos criar uma factory method dentro da raiz do agregado, como clientes externos tem acesso apenas a raiz do agregado, quando este objeto for pedido, a raiz se encarregará de criá-lo e manter a integridade do agregado.
Se um objeto interno ao agregado precisar de uma fábrica, e a raiz do agregado não for um lugar adequado, devemos criar uma classe implementando uma fábrica para a criação deste objeto.

Além de fábrica para criação de um único objeto, podemos ter fábricas isoladas que geram agregados inteiros, retornam a raiz do agregado e executa todas as suas invariantes.

As fábricas não devem ser utilizadas para todos os casos, há momentos em que uma chamada direta ao construtor é a melhor opção. Um construtor puro deve ser utilizado nas seguintes situações:
  • A classe não é parte de nenhuma hierarquia e não é usada de maneira polimórfica.
  • O cliente pode escolher uma estratégia para criação da classe.
  • A construção não é complicada.
  • O construtor público deve satisfazer todas as invariantes do objeto criado.
    Sabemos que a fábrica deve garantir as invariantes de um objeto ou agregado, mas onde devemos colocar essas invariantes? Em alguns casos tudo que a fábrica tem que fazer é delegar a verificação das invariantes ao próprio objeto que está sendo criado, esta é a melhor opção, já em outras situações podemos colocar as invariantes diretamente na fábrica, isso reduz a quantidade de código aglomerado em um agregado que abrange muitos objetos. 

Nenhum comentário:

Postar um comentário