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