Estratégias de Persistência em Software Orientado a Objetos

Propaganda
Estratégias de Persistência em Software Orientado a Objetos:
Definição e Implementação de um Framework para
Mapeamento Objeto-Relacional
João Carlos da Silva, Marcelo Santos Daibert, Valdete Maria Gonçalves de Almeida,
Alessandreia Marta de Oliveira Julio, Marco Antônio Pereira Araújo
[email protected], [email protected],
[email protected], {amojulio, maraujo}@granbery.edu.br
Faculdade Metodista Granbery
Bacharelado em Sistemas de Informação
Rua Batista de Oliveira, 1145 – CEP 36010-530 – Juiz de Fora/MG
Resumo
A orientação a objetos, com o passar dos anos, vem se tornando o padrão de
desenvolvimento de sistemas de software. Entretanto, os desenvolvedores enfrentam
problemas quando necessitam persistir objetos, uma vez que os bancos de dados
puramente orientados a objetos não são maduros o suficiente e normalmente com
desempenho inferior aos bancos de dados relacionais. Vislumbrando este problema,
este trabalho se propõe a realizar um estudo exploratório e comparativo das
tecnologias de persistência de objetos disponíveis no mercado, incluindo as de banco
de dados orientado a objetos e objeto-relacionais, além de técnicas de mapeamento
objeto-relacional em banco de dados relacionais. Através destes estudos, foi definida e
implementada uma ferramenta de persistência de objetos compatível com o Borland
Delphi: o framework de persistência objeto-relacional DPL (Delphi Persistent Layer).
Palavras Chave: Camada de Persistência, Orientação a Objetos, Mapeamento ObjetoRelacional, Delphi, DPL
Abstract
Object-Oriented has become, throughout the years, the development pattern for
software systems. However, developers have faced problems whenever they need to
persist objects, once purely OO database are not mature enough and normally with
inferior yielding to relational database. In respect to this problem, it has been
proposed to carry out an explanatory and comparative study of technologies of
persistence of objects available in the market, including the OO database and the
relational-object ones, besides the object-relational mapping techniques in relational
database. By means of these studies, it has been defined and implemented a tool of
persistence of objects compatible with Borland Delphi: the object-relational persistence
framework DPL (Delphi Persistence Layer).
Keywords: Persistence Layer, Object-oriented, Object-relational mapping , Delphi,
DPL.
1. Introdução
O paradigma de desenvolvimento orientado a objetos tem sido extensivamente
utilizado na construção de sistemas de software e se tornando, de fato, o padrão para o
desenvolvimento de aplicações.
Os bancos de dados orientados a objeto são mais adequados para a persistência
de objetos manipulados por aplicações orientadas a objeto, devido à utilização do
mesmo paradigma. Porém a indisponibilidade atual destes bancos de dados, seja devido
ao custo, diversidade ou amadurecimento do mercado, faz com que seja necessária a
busca de alternativas para a realização da persistência.
O modelo de armazenamento relacional é largamente utilizado e difundido no
mercado, contando com diversos produtos e tecnologias maduras e eficientes. Sendo
assim, existe uma forte tendência de utilização de bancos de dados relacionais para
armazenamento dos objetos de aplicações orientadas a objetos. Porém, existem
diferenças significativas do paradigma orientado a objetos para o modelo relacional.
Para que seja possível obter os benefícios de ambos, é necessária uma compatibilidade
entre esses modelos.
Vislumbrando este problema, este trabalho se propôs a realizar um estudo
exploratório e comparativo das tecnologias de persistência de objetos disponíveis no
mercado, incluindo tecnologias de bancos de dados orientado a objetos, objetorelacionais, além de técnicas de mapeamento objeto-relacional em banco de dados
relacionais.
Foi realizado um levantamento de soluções de gerenciamento de banco de dados
e de frameworks de mapeamento objeto-relacional para avaliação de viabilidade na
utilização prática no desenvolvimento de projetos. Visando testar as soluções
encontradas, foi implementado um sistema para estudo de caso compatível com as
várias estratégias de persistência. Este estudo de caso surgiu de um processo de
reengenharia de um sistema existente de controle acadêmico construído através de uma
abordagem estruturada.
Inicialmente foram analisados o banco de dados pós-relacional Caché [1, 2, 3, 4,
5], desenvolvido pela Intersystems e alguns frameworks de mapeamento objetorelacional do mercado [6, 7, 8]. Os estudados foram o DePO (Delphi Persistent Object)
[9], o IO (Instant Objects) [10] e o TiOPF (TechInside Object Persistence Framework).
Todos compatíveis com o ambiente Borland Delphi de Desenvolvimento.
Com os dados obtidos a partir deste estudo realizado foi definida e
implementada uma nova ferramenta de persistência de objetos compatível com o
Borland Delphi: o framework de persistência objeto-relacional DPL (Delphi Persistent
Layer) [11].
Diante disso, este trabalho está dividido em cinco seções além desta introdução.
A seção 2 define mapeamento objeto-relacional. Na seção 3 são apresentados os
conceitos de camadas de persistência. A seção 4 apresenta a camada desenvolvida no
escopo deste trabalho, a DPL. Já na seção 5 é apresentado um estudo de caso e, na seção
6, as considerações finais.
2. Mapeamento Objeto-Relacional
O mapeamento objeto-relacional é uma abordagem que permite a construção de
sistemas utilizando o paradigma orientado a objetos com a persistência destes objetos
em bancos de dados relacionais. Utilizando-se de técnicas e estratégias específicas, é
possível mapear classes com seus atributos e associações para o modelo relacional
(Figura 1).
Tabelas
Classes
Figura 1. Mapeamento Objeto-Relacional
Utiliza-se uma abstração bastante intuitiva no sentido de que uma classe pode
ser mapeada para uma tabela no banco de dados relacional e atributos da classe para
campos da tabela. Porém, algumas diferenças entre os dois modelos, como OID (Object
Identifiers - identificador de objetos), tipos de dados, herança e associações, demandam
um estudo mais detalhado das estratégias de mapeamento.
2.1 OIDs (Object Identifiers)
Existem várias estratégias para atribuir OIDs para objetos, inclusive pode-se
criar uma ou mais classes cuja responsabilidade específica é a de atribuir OIDs para
objetos, sendo estas estratégias separadas das classes que implementam as regras de
negócio.
É considerada uma boa prática de desenvolvimento separar a estratégia de
atribuição de OIDs das classes de negócio, evitando utilizar um atributo qualquer da
classe para ser o identificador. Identificadores que possuem um significado de negócio,
certamente mudam em algum momento [12], pois as regras de negócio mudam
freqüentemente, e o esforço necessário para realizar esta modificação pode ser
imensurável.
Dentre as várias formas de gerar OIDs, pode-se por exemplo utilizar recursos do
próprio sistema gerenciador de bancos de dados para gerar números seqüenciais
automaticamente e utilizá-los como OIDs. Pode-se utilizar conjuntos de números
inteiros, criar algoritmos sofisticados ou utilizar algoritmos já existentes como GUID’s
(Globally Unique IDentifier) ou UUID’s (Universal Unique Identifier) disponibilizados
pela Microsoft e Digital Equipment respectivamente [12].
Uma importante questão em relação aos OIDs está na escolha da estratégia
utilizada para gerá-los. A utilização de estratégias proprietárias pode limitar a utilização
e portabilidade da aplicação, pois nem todas as estratégias são possíveis em todas as
plataformas de hardware e software. Porém, implementar uma estratégia própria que
garanta a unicidade dos OIDs em diversos ambientes, principalmente em ambientes
cliente-servidor e de objetos distribuídos não é uma tarefa trivial, devido ao volume de
transações concorrentes ou distribuição do gerador de OIDs.
2.2 Mapeamento de Classes em Tabelas
O mapeamento de classes pode ser feito mediante a paridade entre classe e
tabela, ou seja, uma classe é mapeada para uma tabela [12]. Este mapeamento direto de
classes para tabelas representa a forma mais simples de mapeamento, tornando mais
fácil o entendimento e a manutenção de uma aplicação. Com um modelo de classes
bastante simples isto poderia ser feito.
Porém, nem sempre é simples assim. No caso de uma estrutura hierárquica,
várias classes podem ser mapeadas para uma tabela, como também uma classe pode ser
mapeada para várias tabelas. Ainda, classes com atributos multivalorados ou compostos
podem ser mapeadas para mais de uma tabela.
2.3 Mapeamento de Atributos em Colunas
Ao tratar do mapeamento de atributos de uma classe para colunas em tabelas de
um banco de dados relacional, deve-se levar em conta que os atributos podem ser de
tipos de dados simples como inteiros, ponto flutuante, caracteres, boleanos e binários,
mas também podem ser de tipos de dados complexos como tipos baseados em outras
classes. Os atributos podem ser ainda multivalorados, o que viola as regras de
normalização do modelo relacional. Além disso, podem existir atributos de controle ou
utilizados em cálculos, que geralmente não necessitam ser mapeados [12].
Desta forma, os atributos simples podem ser mapeados diretamente para colunas
em uma tabela, já os atributos complexos e multivalorados podem necessitar de tabelas
adicionais para seu armazenamento. Estes atributos complexos geralmente possuem
características recursivas, ou seja, são classes que possuem outros atributos e assim
sucessivamente.
2.4 Mapeamento de Herança
Existem fundamentalmente três estratégias para mapear herança em um banco
de dados relacional [13], exemplificado pela Figura 2:
uma tabela por hierarquia: mapear toda a hierarquia de classes para uma
tabela, onde todos os atributos das classes da hierarquia são armazenados
nesta única tabela. A desvantagem desta estratégia é que toda vez que um
objeto da hierarquia for persistido no banco, é necessário persistir também
os valores das demais classes vazios, causando uma grande quantidade de
campos inutilizados. Entretanto o acesso ao banco para a manipulação dos
dados é mais rápido, uma vez que todos os dados estão em somente uma
tabela. É adicionada uma coluna na tabela que referencia qual o tipo do
objeto, ou seja, de qual classe aqueles dados pertencem;
uma tabela por classe concreta: cada classe concreta mapeada vira uma
tabela com todos os atributos herdados das super classes abstratas. A
vantagem desta estratégia é a facilidade de manipulação de dados, uma vez
que todos os dados de cada classe estão em apenas uma única tabela. Como
desvantagem, destaca-se que quando se modifica uma classe abstrata, é
necessário modificar todas as tabelas geradas pelas classes filhas no modelo
relacional;
uma tabela por classe: cada classe é mapeada para uma tabela.
Uma tabela por Uma Tabela por
Classe Concreta
hierarquia
Uma Tabela por
Classe
Figura 2. Estratégias de Mapeamento para Herança
2.5 Mapeamento de Associações
As associações entre classes no modelo orientado a objetos é conceitualmente
bastante similar ao relacionamento entre tabelas no modelo relacional. Este fato permite
que tais associações sejam mapeadas para relacionamentos, podendo utilizar chaves
estrangeiras ou tabelas auxiliares [13].
2.5.1. Associações do Tipo 1:1
A associação do tipo 1:1 entre classes é mapeada colocando o atributo
identificador da classe referenciada na classe que o referencia, criando então o conceito
de uma chave estrangeira no modelo relacional [13], como demonstrado na Figura 3.
Figura 3. Mapeamento de Associação do Tipo 1:1
2.5.2. Associações do Tipo 1:n
Da mesma forma que a associação do tipo 1:1, o relacionamento 1:n também é
mapeado colocando o atributo identificador da classe referenciada na classe que o
referencia, criando então o conceito de uma chave estrangeira no modelo relacional
[14], como demonstrado na Figura 4.
Figura 4. Mapeamento de Associação do Tipo 1:n
2.5.3. Associações do Tipo n:n
Para mapear uma associação do tipo n:n, é necessário utilizar o conceito de
tabela associativa, cujo propósito é manter o relacionamento entre duas ou mais tabelas
do modelo relacional [13].
Cria-se então uma tabela associativa com os OID’s das classes que se
referenciam, garantindo a navegabilidade do relacionamento, como exemplificado na
Figura 5.
Figura 5. Mapeamento de Associação do Tipo n:n
2.6 Mapeamento de Associações Todo/Parte
As associações todo/parte geralmente são representadas como agregações ou
composições. As agregações são associações que representam uma relação
grupo/membro, ou seja, onde o objeto agregado pode existir independente dos objetos
que o constituem. Já a composição representa um tipo de associação onde o todo não
existe sem sua(s) parte(s). Neste caso, tanto agregações quanto composições são
mapeadas para tabelas de duas formas: utilizando uma única tabela com todos os
atributos da classe que representa o todo e das classes que representam suas partes, ou
mais de uma tabela, uma para cada classe envolvida no modelo [14].
3. Camadas de Persistência
O termo camada é muito é utilizado por desenvolvedores de sistemas que
desejam construir aplicações com maior grau de manutenibilidade, encapsulando
funcionalidades e diminuindo assim o acoplamento dentro da aplicação. Na utilização
do paradigma orientado a objetos, alguns padrões de projeto auxiliam na construção de
aplicações em camadas, como por exemplo, o padrão Layer e o MVC (Model-ViewController), dentre outros [13].
Existem vários arranjos possíveis destas camadas, e a quantidade delas não é
pré-determinada, dependendo do tamanho da aplicação e da arquitetura desejada.
Porém, certamente, quanto menor o número de camadas, melhor é o desempenho da
aplicação [13]. Desta forma o equilíbrio entre o número de camadas e sua arquitetura
traz benefícios à manutenibilidade do sistema com um mínimo de impacto no seu
desempenho.
Já persistência é a habilidade de um objeto sobreviver ao ciclo de vida do
processo no qual ele reside [15]. Objetos que morrem com o fim de um processo são
chamados transientes.
A Figura 6 apresenta uma arquitetura em camadas de uma aplicação utilizando o
modelo MVC, que separa em camadas a aplicação, para diminuir a dependência entre as
classes de interface e de negócio.
Classes de Interface com usuário (View)
Modelo
MVC
Classes de Controle (Controller)
Classes de Negócio (Model)
Classes
de
sistema
Camada de Persistência
Banco de
Dados
Figura 6. Arquitetura de um Aplicativo em Camadas
A camada de persistência encontra-se entre a camada de negócio (onde estão as
classes de domínio da aplicação, ou seja, classes que definem as regras de negócio) e o
banco de dados, permitindo que o impacto das modificações em uma delas seja
atenuado em relação à outra. Isto diminui o grau de dependência do banco de dados,
aumentando o grau de manutenibilidade. Toda responsabilidade por persistir objetos
fica a cargo da camada de persistência, liberando a aplicação destas tarefas, aumentando
a produtividade no desenvolvimento [16].
Na camada de persistência está a definição das estratégias de mapeamento do
modelo orientado a objetos para o modelo relacional, discutidas anteriormente. As
estratégias de mapeamento podem estar implícitas nas classes que compõem a camada,
porém neste caso, a escolha de determinada estratégia em detrimento de outra, traz uma
inflexibilidade na própria camada, pois para mudar de estratégia é necessário modificar
a camada. Porém, é possível isolar da camada de persistência as definições das
estratégias de mapeamento, de forma que as estratégias possam ser modificadas ao
longo do tempo, de acordo com as necessidades. A utilização de documentos XML
(Extensible Markup Language) é uma das possíveis formas de armazenamento das
definições das estratégias de mapeamento. Pode-se também utilizar arquivos texto ou
até mesmo tabelas do próprio banco de dados como estratégia de mapeamento.
4. A Ferramenta DPL (Delphi Persistent Layer)
Para este trabalho, o Delphi foi adotado como linguagem de desenvolvimento da
DPL devido a sua adequação ao paradigma da orientação a objetos. Além disto, para
este ambiente não existem tantas opções de persistência como para outros ambientes
como Java. Isto dificulta a adoção efetiva do paradigma orientado a objetos no
desenvolvimento de aplicações de Delphi.
A construção da DPL seguiu uma abordagem de desenvolvimento através do
ciclo de vida espiral, permitindo separar o processo de construção em etapas e de
maneira evolutiva. Desta forma, funcionalidades são implementadas a cada iteração.
Para divisão das fases foi considerado o modelo proposto por Scott Ambler para
construção de camadas de persistência [13]. Baseado neste modelo, o desenvolvimento
da DPL encontra-se concluído até a segunda etapa (milestone), o que permite a
realização das operações básicas de persistência como: criar, recuperar, atualizar e
excluir objetos (CRUD), além de tratar as associações de classes, como demonstrado na
Figura 7.
Fases de Evolução
da Camada
6
DPL
Final
5
4
3
2
1
Legenda:
1. Operações CRUD
2. Suporte para associações
3. Busca por critérios
4. Suporte para cursores, proxies, registros e
cache
5. Aplicação de administração
6. Suporte a transações
Figura 7. Fases de evolução da DPL
A Figura 7 ilustra a evolução da DPL segundo um ciclo de vida em espiral,
dividido em seis fases. Na primeira fase a DPL oferece as operações básicas de
persistência (Create, Read, Update e Delete) que permite persistir e recuperar objetos
individualmente. Na segunda fase é possível tratar associações dos objetos, podendo
então persistir e recuperar de maneira simples objetos associados. Na terceira fase é
possível determinar critérios para recuperação e processamento de conjuntos de objetos.
Na quarta fase pode-se utilizar cursores, proxies, cache e registros para otimizar o
desempenho da camada. Na quinta fase é implementada uma aplicação de administração
da DPL que permita uma interação amigável ao desenvolvedor na configuração da DPL,
definição das estratégias de mapeamento, construção automática de classes de domínio
e tabelas do banco de dados relacional, entre outras. A sexta e última fase trata de
implementação do controle de transações bem como concorrência.
A lista de requisitos a seguir encontra-se implementada, onde alguns destes itens
foram implementados parcialmente, porém de maneira completamente funcional, de
forma que a DPL pode ser utilizada para a construção de aplicações simples orientadas a
objetos [13]:
suportar a arquitetura de aplicação em n-camadas;
implementar o uso da tecnologia DBExpress para acesso aos bancos de
dados relacionais;
gerenciar conexões com o banco de dados relacional;
realizar automaticamente o mapeamento de classes e atributos para tabelas e
campos respectivamente no banco de dados relacional, sendo gerada uma
tabela por classe existente na aplicação;
mapear agregações, associações (um-para-um, um-para-n e n-para-n) e
composições de classes para relacionamento entre tabelas no banco de dados
relacional;
mapear herança de classes para tabelas no banco de dados relacional;
gerar automaticamente identificadores de objetos;
implementar as operações básicas para os objetos persistentes, seguindo o
padrão CRUD;
recuperar todos os objetos persistentes automaticamente de uma classe;
retornar coleções de registros como resultado de requisições de recuperações
visando evitar overhead de conversão de registros de bancos de dados em
objetos e depois em registros novamente.
Para aplicações mais complexas é necessária a evolução da DPL, podendo seguir
as demais fases propostas por Scott Ambler, com incorporação de outros requisitos
descritos no projeto.
Atualmente, aplicações que utilizam classes com ou sem herança, associações
um-para-um e um-para-n são ideais para avaliação da DPL.
A DPL foi projetada para atender à necessidade de troca do banco de dados
relacional utilizado para armazenamento dos objetos, desde que este atenda ao padrão
SQL ANSI. Desta forma, foi utilizado o componente DBExpress que permite, de
maneira simples, a troca do driver utilizado na comunicação com o banco de dados.
Embora o DBExpress dê uma certa flexibilidade à DPL, este exige por sua vez a
utilização de drivers compatíveis com a sua tecnologia, o que é uma certa limitação.
Devido ainda, à implementação de alguns requisitos estarem definidos em fases
de desenvolvimento mais adiantadas, é necessária a criação e manutenção manual tanto
do banco de dados e suas tabelas, bem como do arquivo XML que guarda informações
do mapeamento objeto-relacional.
O tratamento de tipos de dados não primitivos, assim como requisitos
relacionados a desempenho, concorrência e transações, estão alocados para
implementação em fases mais adiantadas na construção da DPL.
4.1 Armazenamento das Estratégias de Mapeamento Objeto-Relacional em XML
As estratégias de mapeamento objeto-relacional definem o funcionamento
essencial da DPL. De forma a tornar flexível a manutenção destas estratégias, encontrase fora do código da DPL, ou seja, estão armazenadas em um arquivo externo do tipo
XML, utilizado pela DPL.
Este arquivo XML contém basicamente metadados das classes da aplicação, bem
como suas associações, e principalmente a correspondência para estruturas do banco de
dados relacionais (tabelas e campos).
A Listagem 1 demonstra que o arquivo XML está centrado nas informações das
classes, seus atributos e associações. E ainda onde estes elementos da orientação a
objetos estão mapeados no banco de dados relacional. A estrutura do arquivo XML
facilita a leitura das informações por parte da DPL através de um conjunto de tags prédefinidas. A validação desta estrutura pode ainda ser feita com uso de XML Schema,
permitindo maior integridade das informações.
Listagem 1. Mapeamento XML para a DPL
01: <?xml version="1.0" encoding="iso-8859-1"?>
02: <mapeamento>
03:
<classes>
04:
<classe>
05:
<nomeclasse>Curso</nomeclasse>
06:
<heranca></heranca>
07:
<tabela>Curso</tabela>
08:
<tipo>Concreta</tipo>
09:
<atributos>
10:
<atributo>
11:
<nome>ID</nome>
12:
<OID>TRUE</OID>
13:
<campo>OID</campo>
14:
<tipodado>STRING</tipodado>
15:
<tamanho>38</tamanho>
16:
</atributo>
17:
<atributo>
18:
<nome>codigocurso</nome>
19:
<OID>FALSE</OID>
20:
<campo>cod_curso</campo>
21:
<tipodado>INTEGER</tipodado>
22:
<tamanho></tamanho>
23:
</atributo>
24:
</atributos>
25:
<associacoes>
26:
<classeassociada>
27:
<nomeclasse>Disciplina</nomeclasse>
28:
<tipoassociacao>agregation</tipoassociacao>
29:
<cardinalidade>one</cardinalidade>
30:
<atributoinverso>curso</atributoinverso>
31:
</classeassociada>
32:
<classeassociada>
33:
<nomeclasse>Professor</nomeclasse>
34:
<tipoassociacao>one-to-one</tipoassociacao>
35:
<cardinalidade>one</cardinalidade>
36:
<atributoinverso>curso</atributoinverso>
37:
</classeassociada>
38:
</associacoes>
39:
</classe>
40:
</classes>
41: </mapeamento>
A DPL realiza na fase inicial da aplicação o carregamento das informações
do arquivo XML de mapeamento. As informações obtidas são armazenadas em um
conjunto de classes que facilitam ainda mais a leitura e navegação pelo mapa de classes
da aplicação, além de evitar o acesso constante ao disco rígido, o que afetaria o
desempenho da DPL. Este conjunto de classes, por sua vez, faz parte de uma arquitetura
implementada pela DPL para facilitar a interação com as aplicações.
4.2 Arquitetura da DPL
Existem diversas classes que formam a arquitetura básica da DPL, sendo: OID,
TDPLPersistentObject,
TDPLPersistenceBroker,
TDPLPersistenceMapXML,
TDPLRelationalDatabase e TDPLSQLStatement. O diagrama de classes da DPL pode
ser visto na Figura 8, onde os atributos e serviços foram suprimidos para facilitar a
visualização do modelo.
Figura 8. O diagrama de classes da DPL
A classe OID é responsável por gerar identificadores únicos para os objetos
instanciados. Como tais identificadores podem ser criados a partir de diversas
abordagens, a utilização desta classe permite que futuramente a forma de gerar os OIDs
possa ser modificada independente do funcionamento da DPL. Atualmente o algoritmo
utilizado para criação do OID é baseado no GUID (Globally Unique Identifier). O
GUID é representado por um conjunto de caracteres hexadecimais, cuja formação
garante a unicidade do identificador gerado [13].
A classe TDPLPersistentObject é uma das classes principais na arquitetura da
DPL. Através dela, e somente dela, a aplicação orientada a objetos recebe por herança
toda a capacidade de persistência. Esta classe associa-se na arquitetura às outras classes
de maneira a permitir que as informações dos objetos sejam persistidas em bancos de
dados relacionais, através da geração de expressões SQL, comunicação e envio destas
expressões ao banco de dados relacional, dentre outras atividades.
A classe TDPLPersistenceBroker é responsável pela interação com o banco de
dados relacional bem como tarefas de inicialização da DPL. Desta forma implementa
operações que coordenam a carga do mapa XML, a inicialização do banco de dados e
envio de expressões SQL ao banco.
A classe TDPLPersistenceMapXML é responsável por carregar em memória as
informações do arquivo de mapeamento XML, permitindo assim o acesso mais rápido
às informações de mapeamento objeto-relacional, além da flexibilidade de mudança no
arquivo, que pode ser recarregado novamente caso necessário.
A classe TDPLSQLStatement é responsável pela geração de expressões SQL
para realização das operações de persistência junto ao banco de dados relacional. Podem
ser geradas várias expressões SQL para uma única operação de persistência, de acordo
com as definições realizadas no arquivo XML. Ou seja, a persistência de um único
objeto pode gerar várias expressões SQL para manutenção em diversas tabelas no
modelo relacional.
A
classe
TDPLRelationalDatabase
tem
como
responsabilidade
o
encapsulamento das funcionalidades do componente DBExpress. Desta forma, esta
classe controla a conexão ao banco de dados, bem como os parâmetros inerentes ao
driver apropriado do banco, a execução das expressões SQL e desconexão do banco.
O funcionamento coordenado das classes acima mencionadas, cada qual com
responsabilidades bem definidas, permitindo abstrair da aplicação as tarefas
relacionadas à persistência de objetos.
5. Estudo de Caso
Como estudo de caso foi adotado o Sistema de Controle Acadêmico (SCA) que é
utilizado em algumas disciplinas do curso de Sistemas de Informação da Faculdade
Metodista Granbery, sendo um dos motivos pelo qual foi escolhido. O préconhecimento das características do SCA foi um facilitador para a equipe, para poder
então se concentrar nos aspectos relativos à construção e implementação da DPL.
Porém, para a adequação do Sistema de Controle Acadêmico, visto que o mesmo
originalmente foi construído de forma estruturada, foi necessária a realização de uma
reengenharia do sistema para torná-lo aderente ao paradigma orientado a objetos, o que
permitiu a elaboração de uma documentação completa deste sistema seguindo o padrão
IEEE std 830-1998 para especificação de requisitos.
5.1 Desenvolvimento do Sistema de Controle Acadêmico
O SCA seguiu algumas fases de desenvolvimento de forma que pudesse estar
preparado para utilização com a DPL. Como citado anteriormente, na fase inicial sofreu
uma reengenharia com objetivo de torná-lo orientado a objetos e ao mesmo tempo
produzir uma documentação padronizada e completa, consistindo da elaboração dos
diagramas de casos de uso, de classes e de seqüência, utilizando a simbologia da UML
(Unified Modeling Language).
O Sistema de Controle Acadêmico foi então desenvolvido em uma única versão
capaz de utilizar as diversas estratégias de persistência envolvidas neste trabalho. Por
isso, sua implementação contém códigos padronizados e genéricos compatíveis a todas
as estratégias abordadas (DPL, frameworks de persistência e banco de dados objetorelacional Caché). Desta forma, e obedecendo ao padrão MVC, foram implementadas as
camadas View (formulários e relatórios) e Controller (denominada gerente). Estas duas
camadas são únicas para todas as abordagens. Apenas a camada Model foi
implementada de acordo com cada abordagem, não interferindo nas demais.
A camada Controller implementa gerentes para cada caso de uso, tendo como
responsabilidade intermediar as solicitações e envios de objetos entre as camadas Model
e View, de forma genérica o bastante para permitir a troca da implementação feita na
camada Model, sem necessidade de modificações na camada View. A camada
Controller transfere objetos do tipo ClientDataset, criados dinamicamente, em resposta
a solicitações e envios de dados dos objetos, permitindo maior independência entre as
camadas.
Na camada Model foram implementadas as classes da aplicação. No caso da
implementação com a DPL foram criadas as classes que herdam de uma superclasse
comum chamada TDPLPersistentObject. Esta característica define a camada como
sendo intrusiva, pois exige a realização da herança. Porém, o SCA foi preparado não
somente para esta abordagem como também para a não intrusiva, como no caso da
utilização do banco de dados Caché.
A abordagem de uso do padrão MVC não é uma obrigatoriedade para
implementação com a DPL, nem mesmo com as demais estratégias. Porém, o desafio de
construção deste tipo de aplicação foi um motivador a mais durante o projeto de
pesquisa.
Sendo assim, o Sistema de Controle Acadêmico foi desenvolvido em camadas
separadamente até a implementação dos gerentes para cada caso de uso. Posteriormente,
foram implementadas as camadas de modelo para cada abordagem. Sendo então a única
diferença entre cada abordagem, a camada Model.
5.2 Implementação do Sistema de Controle Acadêmico com a DPL
Como uma das fases iniciais da implementação da DPL no Sistema de Controle
Acadêmico, destaca-se a construção do arquivo XML de mapeamento objeto-relacional.
De posse da documentação do SCA, em especial do diagrama de classes, foi possível
construir o arquivo de mapeamento.
Como o banco de dados sofreu alterações mínimas (basicamente inclusão de
campos para OIDs) da versão original construída através do paradigma estruturado para
a versão orientada a objetos, os diagramas como DER (Diagrama de Entidade e
Relacionamentos) e DTR (Diagrama de Tabelas Relacionais) serviram também como
base para elaboração do arquivo XML de mapeamento objeto-relacional.
O estudo de caso relacionado à implementação com a DPL descrito neste
trabalho concentra-se em apenas um fragmento do SCA, tendo sido escolhido o caso de
uso Cadastrar Curso, pois possui classes e associações cujas características são
apropriadas para o teste das funcionalidades implementadas na DPL.
Como o próprio nome já indica, o caso de uso Cadastrar Curso permite a
manutenção (pesquisa, inclusão, alteração, exclusão e consulta) de cursos no Sistema de
Controle Acadêmico. Na documentação completa do SCA, este caso de uso faz parte
dos cenários da Secretaria, que trata de funcionalidades realizadas pela secretaria de
uma instituição de ensino. A Figura 9 mostra um fragmento do diagrama de classes do
Sistema Acadêmico, considerando apenas as classes relacionadas a este caso de uso. Os
atributos foram retirados para facilitar a leitura do modelo.
Pessoa
Criar()
Pers is tir()
Excluir()
RecuperaObjeto()
RecuperaObjetos ()
Curs o
Criar()
Pers is tir()
Excluir()
RecuperaObjeto()
RecuperaObjetos ()
1
0..*
Coordena
Profes s or
1
Aloca
0..*
Figura 9. Fragmento do diagrama de classes do Sistema Acadêmico
A classe Pessoa é uma classe abstrata e possui atributos que são comuns às
classes Professor e Aluno. Esta classe, bem como a classe Curso, herda diretamente da
classe TDPLPersistentObject recebendo assim a capacidade de persistência oferecida
pela DPL. A classe Professor por sua vez recebe esta capacidade de persistência de
maneira indireta, ou seja, pela herança de Pessoa.
As classes implementam propriedades para cada atributo, sendo esta uma
obrigatoriedade para implementação com a DPL. As propriedades substituem os
métodos get e set, necessários para modificar dados dos objetos sem desrespeitar o
princípio do encapsulamento. Embora não seja necessário, podem-se criar propriedades
que acionam métodos get e set caso queira-se respeitar à risca o padrão de uso destes
tipos de métodos. As propriedades devem ter o mesmo nome utilizado internamente no
arquivo XML de mapeamento para referenciar os campos das tabelas.
As classes Professor e Curso implementam os serviços Criar, Excluir, Persistir,
RecuperaObjeto e RecuperaObjetos, que acionam serviços correspondentes nos gerentes
permitindo a realização das respectivas operações, sendo o serviço RecuperaObjetos
responsável pela recuperação de todos os objetos da classe.
A classe Curso implementa a associação do tipo um-para-um com Professor,
adicionando um atributo cujo tipo refere-se a este último, da mesma forma como
especificado no arquivo XML. Ao identificar o tipo de dado do atributo como sendo
uma classe, a DPL verifica se esta faz parte da hierarquia de TDPLPersistentObject.
Caso isto seja verdadeiro, o objeto relacionado ao atributo é instanciado
automaticamente e recebe o OID correspondente. Observa-se que somente o OID é
recuperado, pois é o suficiente para identificar o objeto e posteriormente pode ser
recuperado por completo.
Um único gerente é instanciado no momento da execução de cada operação e
este instância um objeto da classe Curso obtendo ou transferindo a ele os dados para
persistência. Tal transferência acontece de maneira transparente ao desenvolvedor da
aplicação. Os dados da interface são alocados em um ClientDataSet o qual é entregue ao
gerente e solicitado à persistência. Ou, é solicitado ao gerente a recuperação dos dados,
que são recebidos em um ClientDataSet. Desta forma a programação da interface é
simplificada de forma que o desenvolvedor não necessite conhecer como e onde os
dados são persistidos.
O caso de uso Cadastrar Curso, bem como todos os demais, foi especificado em
termos de seu Fluxo Principal, Alternativos e de Exceções, além de sub-fluxos
representando as operações básicas de inclusão, alteração, exclusão e consulta. A
interface principal deste caso de uso considerando o sub-fluxo de inclusão pode ser vista
na Figura 10.
Figura 10. Interface Principal do Caso de Uso Cadastrar Curso
6. Considerações Finais
A persistência de objetos é um tema importante quando se fala em
desenvolvimento de sistemas orientados a objetos. As dificuldades atuais inerentes à
utilização de bancos de dados orientados a objetos levam a busca de alternativas para a
realização da persistência. Devido à grande inserção no mercado, os bancos de dados
relacionais são uma possível alternativa.
Ao determinar a utilização do modelo relacional para persistência de objetos,
deve-se levar em consideração a diferença existente entre estes dois paradigmas,
orientado a objetos e relacional.
O mapeamento objeto-relacional apresenta diversas estratégias para reduzir a
diferença entre os dois paradigmas, a partir do mapeamento de classes, atributos e
associações em tabelas, campos e relacionamentos. As estratégias não apresentam
solução única para cada caso, mas devem levar em consideração características do
modelo de classes, questões como manutenibilidade e desempenho.
A construção de camadas de persistência, embora não seja trivial, mostra-se
possível, através da DPL, e podem ser obtidos resultados visíveis com a sua
implementação. O domínio de temas como engenharia de software, padrões de projeto e
orientação a objetos, entre outros, mostra-se extremamente necessário para acomodar o
processo de desenvolvimento de um framework de persistência.
Agradecimentos
À Faculdade Metodista Granbery pelo apoio dado ao projeto de iniciação
científica Estratégias de Persistência em Software Orientado a Objetos, no qual este
trabalho está inserido.
Referencias Bibliográficas
[1]
[2]
[3]
[4]
[5]
[6]
ALMEIDA, V. M. G. Persistência de Objetos no Banco de Dados Caché.
Trabalho de Conclusão de Curso, Bacharelado em Sistemas de Informação –
Faculdade Metodista Granbery, Juiz de Fora, 2005.
ALMEIDA, V. M. G.; JULIO, A. M. O.; ARAÚJO, M. A. P. Persistência de
Objetos no Caché. SQL Magazine, Rio de Janeiro, v. 22, p. 16-21, 2005.
ALMEIDA, V. M. G.; JULIO, A. M. O.; ARAÚJO, M. A. P. Implementando
um Projeto no Caché. SQL Magazine, Rio de Janeiro, v. 25, p. 8-14, 2005.
ALMEIDA, V. M. G.; JULIO, A. M. O.; ARAÚJO, M. A. P. Desenvolvendo
Aplicações Web no Caché. SQL Magazine, Rio de Janeiro, v. 29, p. 60-62,
2005.
SILVA, J. C.; ARAÚJO, M. A. P.; JULIO, A. M. O. Delphi X Caché Persistindo Objetos no Banco de Dados Caché. Active Delphi, v. 28, p. 10-16,
junho, 2006.
DAIBERT, M. S. Persistência em Software Orientado a Objetos: Soluções
de Mapeamento Objeto-Relacional. Trabalho de Conclusão de Curso,
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]
Bacharelado em Sistemas de Informação – Faculdade Metodista Granbery, Juiz
de Fora, 2005.
DAIBERT, M. S.; JULIO, A. M. O.; ARAÚJO, M. A. P. Persistência em
Software Orientado a Objetos: Abordagens Utilizando Frameworks
Opensource. In: II FESTSOL - Festival de Software Livre, Juiz de Fora, 2005.
DAIBERT, M. S.; JULIO, A. M. O.; ARAÚJO, M. A. P. Persistência em
Software Orientado a Objetos: Abordagens Utilizando Frameworks
Opensource. In: III Encontro de Software Livre do Amazonas (ESLAM),
Manaus, 2005.
DAIBERT, M. S.; JULIO, A. M. O.; ARAÚJO, M. A. P. Persistência de
Objetos no Delphi: Introdução ao Framework DePO (Delphi Persistent
Objects). Active Delphi, v. 24, p. 16 - 21, fevereiro, 2006.
DAIBERT, M. S.; JULIO, A. M. O.; ARAÚJO, M. A. P. Persistência de
Objetos no Delphi: Introdução ao Framework IO (Instant Objects). Active
Delphi, v. 25, p. 30 - 34, março, 2006.
SILVA, J. C. Camada de Persistência Objeto-Relacional para Delphi. 2005,
Trabalho de Conclusão de Curso, Bacharelado em Sistemas de Informação –
Faculdade Metodista Granbery, Juiz de Fora, 2005
AMBLER, S. W. Mapping Object to Relational Databases. 1999. Disponível
em: <http://www.ambysoft.com/mappingObjects.pdf>. Acesso em: 08 jul. 2006
AMBLER, S. W. The Design of a Robust Persistence Layer for Relational
Databases.
Nov.
2000.
Disponível
em:
<
http://www.ambysoft.com/essays/persistenceLayer.html >. Acesso em: 01 jul.
2006.
KELLER, W. Mapping Objects to Tables - A Pattern Language. 1997, 2004.
Disponível em: <http://www.objectarchitects.de>. Acesso em: 08. jul. 2006.
KELLER, W. Persistence Options for Object-Oriented Programs. 2004.
Disponível em: <http://www.objectarchitects.de>. Acesso em: 08. jul. 2006.
YODER, J. W., JOHNSON, R. E., WILSON, Q. D. Connecting Business
Objects to Relational Databases. In Proceedings of the 5th Conference on the
Pattern Languages of Programs, Monticello, 1998. Disponível em:
<http://www.joeyoder.com/Research/objectmappings/Persista.pdf>. Acesso em:
08. jul. 2006.
Download