Padrões JEE – Parte 4

Olá!

Este post trata dos últimos padrões de projeto referentes à camada de negócio. Será um pouco mais longo pelo número de padrões – cinco ao todo – e mais complexo por tratar de alguns tópicos mais avançados da Plataforma JEE, tais como entity beans.  Antes de mais nada, vou tratar aqui de patterns mais voltados para as versões anteriores da tecnologia EJB, tais como 1.x e 2.x.  A versão mais recente – 3.1 – oferece uma alternativa à complexidade dos entity beans: entidades, ou entities, que nada mais são do que classes Java que fazem uso de anotações para mapeamento objeto-relacional, ao estilo de frameworks já conhecidos, como o Hibernate [3] em suas versões mais recentes.  Entretanto, entity beans ainda devem ser obrigatoriamente suportados por containers que implementem as versões 3.x da especificação de Enterprise Java Beans.  Portanto, ainda podem ser cobrados em alguns editais, em especial em órgãos que precisem dar suporte a aplicações legadas.

Vamos aos padrões deste post: Business Object, Composite Entity, Transfer Object, Transfer Object Assembler e Value List Handler.

Business Object

Problema: Tem-se um modelo de domínio conceitual com lógica de negócio e relacionamentos.

Solução: Utilizar Business Objects – objetos de negócio – para separar dados e lógica de negócio usando um modelo de objetos.

Estrutura:

Diagrama de sequência:


Participantes e responsabilidades:

  • Client: tipicamente uma Session Façade, um helper (ver padrão View Helper) ou um Application Service (ver padrão Application Service) que precise acessar o BusinessObject.
  • ParentBO:  objeto top-level que representa o objeto pai no composite de objetos.  O objeto pai encapsula objetos dependentes e implementa sua lógica de negócio intrínsica e regras de negócio.
  • DependentBO:  BusinessObject dependente que é gerenciado pelo ParentBO.  Esses objetos são fortemente acoplados com seus objetos-pai, aos quais delegam o gerenciamento de seus ciclos de vida.  Objetos dependentes não existem sem seus objetos-pai.  Cada objeto dependente implementa suas próprias regras de negócio intrínsicas.

Exemplos de aplicabilidade:

O trecho de código abaixo mostra um Business Object implementado como um POJO – assumindo que a aplicação não faz uso de entity beans.  Veja que esse Business Object, que representa a entidade ClienteBO, possui um objeto dependente – EderecoBO.

Classe EnderecoBO:

Em geral, Business Objects podem implementar validações nos dados de entrada.  Adicionalmente, podem encapsular lógica de persistência, embora isso não seja aconselhado, uma vez que se sugere que código relativo a persistência seja encapsulado em objetos de acesso a dados – ou DAOs.

Outra estratégia possível para o emprego deste pattern é a implementação de Business Object como entity beans – que a grosso modo são objetos Java cujo gerenciamento é realizado por um servidor de aplicação ou container, responsável pela persistência, segurança, controle de transação e concorrência, entre outras responsabilidades.

Composite Entity

Problema: Deseja-se usar entity beans para implementar o modelo de domínio conceitual.

Solução: Usar um Composite Entity para implementar Business Objects (ver padrão Business Object) utilizando entity beans locais e POJOs.  Um Composite Entity agrega um conjunto de Business Objects relacionados em implementações de entity beans de alta granularidade.

Estrutura:

Diagrama de sequência:

Participantes e responsabilidades:

  • Composite Entity: Entity bean de alta granularidade que contém objetos dependentes.
  • DependenteBO, DependentEntityBO e DependentPOJOBO: Objeto que depende do objeto-pai para gerenciar seu ciclo de vida.  Pode conter outros objetos dependentes.  Pode ser implementado como um entity bean local ou como um POJO.
  • DataStore: Representa o repositório onde os dados são persistidos (ex.: banco de dados relacional).
  • EJB Container: Invoca as operações de load e store.  Seu comportamento é prescrito pela Especificação de EJB e atualmente existe várias implementações disponíveis no mercado (ex.: Glass Fish Application Server, JBoss, IBM Webshpere, etc.)

Exemplos de aplicabilidade:

O exemplo abaixo é adaptado do livro Core J2EE Patterns.  Consiste em um business object que representa um recurso de uma aplicação de automação de serviços.  Nessa aplicação, um recurso nada mais é do que um funcionário, que por sua vez possui os seguintes relacionamentos:  BlockOutTime, que indica os períodos de tempo em que o recurso está indisponível (férias, licença, etc.) e SkillSet, que indica o conjunto de habilidades do recurso.  Ambos os relacionamentos são 1 para N.

O código abaixo mostra a estratégia de lazy loading ou carregamento sob demanda, na qual as partes dependentes são carregadas do repositório de dados apenas quando realmente necessário, evitando que se carregue de uma única vez grafos de objetos muito grandes.  Tal estratégia é bastante empregada atualmente por ferramentas de mapeamento objeto-relacional, a exemplo do Hibernate.

Transfer Object

Problema: Deseja-se transmitir múltiplos elementos de dados entre camadas.

Solução: Usar um Transfer Object para carregas múltiplos elementos de dados entre camadas.

Estrutura:

Diagrama de Sequência:

Participantes e responsabilidades:

  • Client:  Elemento que precisa acessar um Component para enviar e receber dados.  Tipicamente, o cliente é um Component em outra camada.
  • Component:  Qualquer componente em outra camada que o cliente acessa para enviar e receber dados.  Pode estar na camada de apresentação, (PresComponent), negócio (BizComponent) ou integração (IntComponent).
  • TransferObject:  POJO serializável que contem vários membros, com a finalidade de transportar todos os dados em uma única chamada de método.

Exemplos de aplicabilidade:

A principal motivação por trás deste pattern está no fato de que, quando se acessa um business object remoto, como por exemplo um entity bean, para recuperar e gravar os dados individuais deste objeto, cada chamada respectivamente a um método get ou set gera uma chamada remota (RPC), o que por sua vez incorrerá em maior tráfego de rede e consequente queda de desempenho da aplicação cliente.  Daí, devem-se substituir tais chamadas por uma única chamada a um método get/setData().

Abaixo, temos um exemplo de código que emprega o padrão Transfer Object.

Transfer Object Assembler

Problema: Deseja-se obter um modelo de aplicação que agrega transfer objects provenientes de vários componentes de negócio.

Solução: Usar um Transfer Object Assembler para construir um modelo de aplicação como um transfer object composto.  O Transfer Object Assembler agrega múltiplos transfer objects provenientes de vários componentes e serviços de negócio e retorna o transfer object resultante para o cliente.  A principal vantagem aqui é centralizar a criação desse objeto, de modo a evitar que tal código seja disseminado pelas aplicações cliente.

Estrutura:

Diagrama de Sequência:

Participantes e responsabilidades:

  • Client: Invoca o TransferObjectAssembler para obter os dados do modelo da aplicação.  Pode ser, por exemplo, um componente na camada de apresentação, um Session Façade ou um Business Delegate.
  • TransferObjectAssembler:  Constrói um novo transfer object composto com base nos requisitos da aplicação, quando o cliente requisita os dados do modelo da aplicação.
  • ApplicationModel:  Transfer object composto que é construído pelo TransferObjectAssembler e retornado para o cliente.
  • BusinessObject:  Fornece transfer objects para o TransferObjectAssembler montar o ApplicationModel.
  • DataAccessObject:  Representa objetos de acesso a dados em cenários onde o TransferObjectAssmbler acessa diretamente os dados persistentes.
  • Service:  Qualquer serviço arbitrário (ex.: um Application Service) na camada de negócio que fornece os dados requeridos para construir o ApplicationModel.

Exemplos de aplicabilidade:

Os trechos de código abaixo mostram um exemplo bastante simples de um Transfer Object Assembler que constrói e retorna os dados de um cliente juntamente com os dados da sua conta, em um sistema bancário.

ApplicationModel:

Transfer Object ClienteTO:

Transfer Object ContaTO:

Transfer Object Assembler:

Value List Handler

Problema: Tem-se um cliente remoto que deseja iterar por uma lista grande de resultados.

Solução: Usar um Value List Handler para buscar, fazer cache dos resultados e permitir ao cliente percorrer e selecionar itens do resultado.

Estrutura:

Diagrama de Sequência:

Participantes e responsabilidades:

  • Client: Qualquer cliente que precise executar uma consulta que retorna um grande conjunto de resultados.
  • ValueListIterator:  Fornece um mecanismo de iteração pelo conteúdo do ValueList – ver padrão Iterator (Gof).
  • ValueListHandler: Executa a busca e armazena o seu resultado em uma coleção representada pelo objeto ValueList.  Tipicamente utiliza um Data Access Object para executar a busca.  Quando o Client requisita os resultados, o ValueListHandler cria uma sub-lista a partir do ValueList original e a envia para o cliente.
  • DataAccessObject:  Utilizado pelo ValueListHandler para acessar a fonte de dados, executar a consulta e recuperar o resultado.
  • ValueList:  Uma coleção que armazena o resultado da consulta.

Exemplos de aplicabilidade:

Uma motivação bastante comum para o emprego deste pattern é que, em cenários onde são utilizados entity beans, os método ejbFinder() retornam uma lista de objetos remotos.  Dependendo da quantidade de objetos retornados, o conjunto inteiro pode gerar um alto tráfego de rede.  Além disso, para recuperar os dados de cada item do conjunto, são necessárias chamadas a métodos remotos, aumentando ainda mais o overhead.

Concluímos com este post o resumo dos padrões relacionados à camada de negócio.  No próximo e último post desta série, finalizarei o assunto Padrões JEE apresentando os padrões da camada de integração.

Até lá!

[1] Core J2EE Patterns – Best Practices and Design Strategies, 2nd Edition.  Depak Alur, John Crupi e Dan Malks.  2003.

[2] Catálogo online de padrões: http://java.sun.com/blueprints/patterns/catalog.htm

[3] Hibernate.  http://www.hibernate.org/

»crosslinked«

Monique Monteiro

Sou Arquiteta de Software (embora já tenha atuado também como Gerente de Projetos), MSc em Ciência da Computação e sou de Recife, mas moro atualmente em Brasília. Estou envolvida na área de TI (mais especificamente desenvolvimento de software) há cerca de 10 anos (contando o período da faculdade, é claro :)), e de lá pra cá sempre gostei de aprender coisas novas relacionadas ao estado da arte em desenvolvimento e Engenharia de Software em geral! Desde dezembro de 2009 estou trabalhando no Tribunal de Contas da União (TCU), como Auditora Federal de Controle Externo.

Você pode gostar...

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *