Vous êtes sur la page 1sur 118

UNIVERSIDADE REGIONAL DE BLUMENAU CENTRO DE CINCIAS EXATAS E NATURAIS CURSO DE CINCIA DA COMPUTAO BACHARELADO

FRAMEWORK PARA MAPEAMENTO OBJETORELACIONAL EM DELPHI

SAMUEL YURI DESCHAMPS

BLUMENAU 2010 2010/2-26

SAMUEL YURI DESCHAMPS

FRAMEWORK PARA MAPEAMENTO OBJETORELACIONAL EM DELPHI

Trabalho de Concluso de Curso submetido Universidade Regional de Blumenau para a obteno dos crditos na disciplina Trabalho de Concluso de Curso II do curso de Cincia da Computao Bacharelado. Prof. Jacques Robert Heckmann, Mestre - Orientador

BLUMENAU 2010 2010/2-26

FRAMEWORK PARA MAPEAMENTO OBJETORELACIONAL EM DELPHI

Por

SAMUEL YURI DESCHAMPS

Trabalho aprovado para obteno dos crditos na disciplina de Trabalho de Concluso de Curso II, pela banca examinadora formada por:

Presidente:

______________________________________________________ Prof. Jacques Robert Heckmann, Mestre Orientador, FURB ______________________________________________________ Prof. Adilson Vahldick, Mestre FURB ______________________________________________________ Prof. Marcos Rogrio Cardoso, Especialista FURB

Membro:

Membro:

Blumenau, 7 de dezembro de 2010

Dedico este trabalho a todos os amigos, especialmente aqueles que me ajudaram diretamente na realizao deste.

AGRADECIMENTOS

A Deus, por de dar vida, fora, sade e disposio. minha famlia pelo apoio e incentivo. Aos meus amigos mais prximos: Andr L. B. Rosa, Joo R. Rodrigues, Leandro da Cunha, Maicon R. Zatelli e Victor A. Muller, que me acompanharam desde o incio do curso. Aos amigos que de alguma forma me ajudaram, e gostaria de destac-los aqui: Andr W. P. Hildinger, Fabiano Oss e Kelvin R. Stinghen. minha namorada, Paula G. Becher, pela compreenso e ajuda na reviso da monografia. Ao meu orientador, Jacques R. Heckmann, por acreditar na minha capacidade e ser meu guia na realizao deste trabalho.

Qualquer tolo poderia escrever cdigo que um computador consegue entender. Bons programadores escrevem cdigo que humanos conseguem entender. Martin Fowler

RESUMO

Este trabalho apresenta o desenvolvimento de um framework de persistncia de objetos que utiliza a tcnica de Mapeamento Objeto-Relacional. Tal framework ser til na construo de sistemas em Delphi 2010 para Windows que interagem com bancos de dados Firebird ou MySQL, expansvel a outros SGBDRs. A persistncia realizada a partir das classes de entidades da aplicao mapeadas atravs de anotaes, uma abordagem mais eficaz que os mapeamentos baseados em arquivos XML. O framework utiliza recursos como RTTI, Custom Attributes, Nullable e tcnicas de persistncia especiais para Mapeamento Objeto-Relacional como OID, mapeamento de herana e de associaes. Alm disso, faz uso de padres de projeto gerais e especficos, como Lazy Load. So explicados todos estes recursos, bem como a especificao do projeto com diagramas da UML e alguns detalhes de implementao. Ao final, so mostrados exemplos de utilizao do framework para desenvolvimento de um sistema. Palavras-chave: Framework. Delphi. Persistncia. Banco de dados. Mapeamento objetorelacional.

ABSTRACT

This work presents the development of an object persistence framework which uses the Object-Relational Mapping technique. Such framework will be useful to develop information systems in Delphi 2010 environment for Windows witch interact with Firebird or MySQL database systems, extensible to other RDBMSs. The persistence is realized from aplication's entity classes mapped by annotations. This is a more efficacious approach than XML-based mappings. The framework uses resources like RTTI, Custom Attributes, Nullable, ObjectRelational Mapping special techniques like OID, inheritance mapping and association mapping. Also uses both general and specific design patterns, like Lazy Load. This document explains all these techniques, as well as the project specification with UML diagrams and some implementation details. At the end, there are shown examples of using the framework to develop a system. Key-words: Framework. Delphi. Persistence. Database. Object-relational mapping.

LISTA DE ILUSTRAES

Figura 1 Encaixe do ORM entre o paradigma relacional e o orientado a objetos ................. 20 Figura 2 Herana de tabela por classe concreta ..................................................................... 21 Figura 3 Herana de tabela nica .......................................................................................... 23 Figura 4 Herana de tabela por subclasse.............................................................................. 24 Quadro 1 Declarao de Atributos Customizados ................................................................. 27 Quadro 2 Anotaes com Atributos Customizados ............................................................... 27 Quadro 3 Construtores em Atributos Customizados ............................................................. 27 Quadro 4 Utilizao dos construtores nos Atributos Customizados ..................................... 28 Quadro 5 Extrao de Atributos Customizados .................................................................... 28 Figura 5 Padro Identity Field ............................................................................................... 31 Figura 6 Padro Identity Map ................................................................................................ 35 Quadro 6 Implementao de mtodos do Identity Map em Java........................................... 36 Quadro 7 Implementao de mtodos do Identity Map em Delphi ....................................... 36 Figura 7 Padro Strategy ....................................................................................................... 37 Figura 8 Padro Singleton ..................................................................................................... 39 Figura 9 Padro Adapter por objeto ...................................................................................... 41 Figura 10 Padro Adapter por classe ..................................................................................... 42 Figura 11 Padro Foreign Key Mapping ............................................................................... 42 Figura 12 Padro Foreign Key Mapping com colees ........................................................ 43 Figura 13 Padro Lazy Load .................................................................................................. 46 Figura 14 A comunicao dentro do MVC ........................................................................... 50 Figura 15 Estados dos objetos e suas transaes no Hibernate ............................................. 51 Figura 16 Diagrama de casos de uso ..................................................................................... 55 Quadro 8 Caso de uso UC01 Construir base de dados ................................... 56 Quadro 9 Caso de uso UC02 Persistir objeto de entidade ....................... 56 Quadro 10 Caso de uso UC03 Combinar objeto de entidade ....................... 57 Quadro 11 Caso de uso UC04 Atualizar objeto de entidade persistido ....................................................................................................... 58 Quadro 12 Caso de uso UC05 Obter objeto de entidade .............................. 58 Quadro 13 Caso de uso UC06 Obter lista de objetos de entidades .... 59

Quadro 14 Caso de uso UC07 Remover objetos de entidades ..................... 60 Figura 17 Diagrama de componentes .................................................................................... 61 Figura 18 Diagrama de classes do gerenciador de objetos .................................................... 61 Figura 19 Diagrama de classes dos aplicadores de comandos .............................................. 63 Figura 20 Diagrama de classes dos geradores de SQL.......................................................... 65 Figura 21 Diagrama de classes do mediador de conexo ...................................................... 67 Figura 22 Diagrama de classes do explorador de metadados ................................................ 68 Figura 23 Diagrama de seqncia do framework para o mtodo Persist ........................ 71 Figura 24 Classes do modelo de anotao ............................................................................. 72 Quadro 15 Exemplo de anotaes em classe de entidade ..................................................... 76 Quadro 16 Implementao do mtodo Persist ................................................................. 80 Quadro 17 Implementao do mtodo GetChangerMembers ......................................... 81 Quadro 18 Implementao do mtodo Delete ................................................................... 82 Quadro 19 Implementao do mtodo GenerateInsert ................................................ 83 Quadro 20 Classes de comandos nos geradores de SQL ....................................................... 84 Quadro 21 Classes auxiliares nos geradores de SQL ............................................................ 85 Quadro 22 Implementao da estrutura Nullable .................................................................. 88 Quadro 23 Implementao da estrutura Proxy ...................................................................... 89 Quadro 24 Implementao do Lazy Load no Proxy .............................................................. 90 Figura 25 Diagrama de classes do estudo de caso ................................................................. 91 Figura 26 Criao de novo projeto no Delphi ....................................................................... 91 Figura 27 Implementao da classe TArtista................................................................... 92 Figura 28 Classe TArtista mapeada no framework.......................................................... 93 Figura 29 Classe TObra mapeada no framework ................................................................. 94 Figura 30 Implementao dos mtodos de acesso da classe TObra .................................... 95 Figura 31 Classe TAlbum mapeada no framework ............................................................... 96 Figura 32 Classes TMusica e TClipe mapeadas no framework ....................................... 97 Figura 33 Tela de cadastro de msicas .................................................................................. 98 Figura 34 Implementao do carregamento dos componentes da tela .................................. 98 Figura 35 Implementao do boto de salvar msica............................................................ 99 Figura 36 Implementao do mtodo para salvar msica no controlador ........................... 100 Figura 37 Configurao do objeto de conexo .................................................................... 101 Figura 38 Exemplos de alterao e excluso de objetos ..................................................... 102

Figura 39 Construo da base de dados .............................................................................. 103 Quadro 25 Implementao das entidades utilizadas nos testes ........................................... 104 Quadro 26 SQL de construo da base de dados ................................................................ 105 Quadro 27 Implementao do teste de persistncia de objetos ........................................... 106 Quadro 28 Cdigo SQL gerado para persistncia de objetos .............................................. 106 Quadro 29 Implementao do teste de obteno de objetos ................................................ 107 Quadro 30 Cdigo SQL gerado para obteno de objetos .................................................. 107 Quadro 31 - Comparao entre caractersticas e funcionalidades dos frameworks ............... 110

LISTA DE TABELAS

Tabela 1 Medio de tempos de persistncia e obteno de objetos ................................... 108

LISTA DE SIGLAS

API - Application Programming Interface BDE - Borland Database Engine BLOB - Binary Large OBject CPF - Cadastro de Pessoa Fsica DAO - Data Access Object DDL - Data Definition Language DML - Data Manipulation Language GUID - Global Unique IDentifier HQL - Hibernate Query Language IDE - Integrated Development Environment IQL - Instant Query Language JPA - Java Persistence API MVC - Model View Controller OID - Object IDentifier OPF - Object Persistence Framework ORM - Object-Relational Mapping RAD Rapid Application Development RDBMS - Relational DataBase Management System RMI - Remote Method Invocation RTL - RunTime Library RTTI - RunTime Type Information SGBD - Sistema Gerenciador de Bancos de Dados SGBDR - Sistema Gerenciador de Bancos de Dados Relacional

SQL - Structured Query Language UML - Unified Modeling Language VCL - Visual Component Library VMT - Virtual Method Table XML - eXtensible Markup Language

SUMRIO

1 INTRODUO .................................................................................................................. 16 1.1 OBJETIVOS DO TRABALHO ........................................................................................ 17 1.2 ESTRUTURA DO TRABALHO ...................................................................................... 17 2 FUNDAMENTAO TERICA .................................................................................... 18 2.1 O PAPEL DO FRAMEWORK ........................................................................................... 18 2.2 MAPEAMENTO OBJETO-RELACIONAL .................................................................... 19 2.2.1 Mapeamento de herana .................................................................................................. 21 2.2.1.1 Herana de tabela por classe concreta .......................................................................... 21 2.2.1.2 Herana de tabela nica ................................................................................................ 22 2.2.1.3 Herana de tabela por subclasse ................................................................................... 23 2.3 RUNTIME TYPE INFORMATION (RTTI) .................................................................... 25 2.4 ATRIBUTOS CUSTOMIZADOS .................................................................................... 26 2.4.1 Declarao de Atributos Customizados .......................................................................... 26 2.4.2 Extrao de Atributos Customizados .............................................................................. 28 2.5 TIPOS ANULVEIS ........................................................................................................ 29 2.6 PADRES DE PROJETO ................................................................................................ 30 2.6.1 Padro Data Access Object (DAO) ................................................................................. 30 2.6.2 Padro Identity Field ....................................................................................................... 30 2.6.2.1 Chaves com ou sem significado ................................................................................... 31 2.6.2.2 Chaves simples versus chaves compostas .................................................................... 32 2.6.2.3 O tipo da chave ............................................................................................................. 32 2.6.2.4 Obtendo uma nova chave.............................................................................................. 32 2.6.2.5 Trabalhando com herana ............................................................................................. 34 2.6.3 Padro Identity Map ........................................................................................................ 34 2.6.3.1 Funcionamento do Mapa de Identidade ........................................................................ 34 2.6.4 Padro Strategy ............................................................................................................... 36 2.6.5 Padro Singleton.............................................................................................................. 38 2.6.6 Padro Adapter ................................................................................................................ 40 2.6.7 Padro Foreign Key Mapping ......................................................................................... 42 2.6.7.1 Mapeamento de colees .............................................................................................. 43 2.6.7.2 Tratamento de ciclos ..................................................................................................... 45

2.6.7.3 Onde no utilizar........................................................................................................... 45 2.6.8 Padro Lazy Load ............................................................................................................ 46 2.6.8.1 Inicializao tardia ........................................................................................................ 47 2.6.8.2 Proxy virtual ................................................................................................................. 47 2.6.8.3 Armazenador de valor ................................................................................................... 48 2.6.8.4 Fantasma ....................................................................................................................... 48 2.6.8.5 Programao orientada a aspectos ................................................................................ 48 2.6.8.6 Escolhendo a melhor estratgia .................................................................................... 49 2.6.9 Padro Model View Controller (MVC) ........................................................................... 49 2.7 TRABALHOS CORRELATOS ........................................................................................ 50 2.7.1 Hibernate ......................................................................................................................... 50 2.7.2 Instant Objects ................................................................................................................ 51 2.7.3 Ferramenta para aplicao do DAO em sistemas desenvolvidos em Delphi .................. 52 3 DESENVOLVIMENTO DO FRAMEWORK .................................................................. 53 3.1 REQUISITOS PRINCIPAIS DO PROBLEMA A SER TRABALHADO ....................... 53 3.2 ESPECIFICAO ............................................................................................................ 54 3.2.1 Comportamento do framework ....................................................................................... 54 3.2.1.1 UC01 Construir base de dados .................................................................................. 55 3.2.1.2 UC02 Persistir objeto de entidade ............................................................................. 56 3.2.1.3 UC03 Combinar objeto de entidade .......................................................................... 57 3.2.1.4 UC04 - Atualizar objeto de entidade persistido ............................................................ 57 3.2.1.5 UC05 Obter objeto de entidade ................................................................................. 58 3.2.1.6 UC06 Obter lista de objetos de entidades .................................................................. 59 3.2.1.7 UC07 Remover objeto de entidade ............................................................................ 59 3.2.2 Estrutura do framework ................................................................................................... 60 3.2.2.1 Gerenciador de objetos ................................................................................................. 61 3.2.2.2 Aplicadores de comandos ............................................................................................. 62 3.2.2.3 Geradores de SQL......................................................................................................... 64 3.2.2.4 Mediador de conexo .................................................................................................... 66 3.2.2.5 Explorador de metadados ............................................................................................. 68 3.2.3 Interao entre as classes ................................................................................................ 70 3.3 MODELO DE ANOTAO PARA MAPEAMENTO ................................................... 71 3.4 IMPLEMENTAO ........................................................................................................ 77 3.4.1 Tcnicas e ferramentas utilizadas.................................................................................... 77

3.4.2 Convenes seguidas ...................................................................................................... 78 3.4.3 Implementao dos componentes do framework ............................................................ 79 3.4.4 Funcionalidades e estratgias implementadas ................................................................. 85 3.4.4.1 Mapeamento de herana ............................................................................................... 85 3.4.4.2 Mapeamento de associaes ......................................................................................... 86 3.4.4.3 Object Identifier ............................................................................................................ 87 3.4.4.4 Nullable......................................................................................................................... 87 3.4.4.5 Lazy Load...................................................................................................................... 89 3.4.5 Operacionalidade da implementao .............................................................................. 90 3.5 RESULTADOS E DISCUSSO .................................................................................... 103 3.5.1 Anlise do SQL gerado ................................................................................................. 103 3.5.1.1 Teste 1 Construo da base de dados....................................................................... 104 3.5.1.2 Teste 2 Persistncia de objetos ................................................................................ 105 3.5.1.3 Teste 3 Obteno de objetos .................................................................................... 107 3.5.2 Anlise de desempenho ................................................................................................. 108 3.5.3 Comparaes com trabalhos correlatos ......................................................................... 109 4 CONCLUSES ................................................................................................................ 113 4.1 EXTENSES .................................................................................................................. 114 REFERNCIAS BIBLIOGRFICAS ............................................................................... 116

16 1 INTRODUO

Com o aumento da quantidade de sistemas de informao sendo construdos nos ltimos anos, surgiram frameworks1 para facilitar e organizar o seu desenvolvimento. O seu objetivo abstrair a implementao das partes mais repetitivas da construo, que normalmente so comuns a qualquer sistema. Em um sistema de informao que utilize um Sistema Gerenciador de Bancos de Dados (SGBD) para persistir as informaes, uma parte do desenvolvimento que normalmente se torna repetitiva a implementao de rotinas que interagem com o SGBD. Em especial, quando se trata de um Sistema Gerenciador de Bancos de Dados Relacional (SGBDR), esta parte geralmente implementada utilizando a Structured Query Language (SQL), que embutida no cdigo da linguagem de programao do sistema. Esta prtica pode tornar-se pouco produtiva, pois h a necessidade de se trabalhar ao mesmo tempo com duas linguagens de diferentes paradigmas: o da orientao a objetos e o relacional. No interessante preocupar-se com detalhes especficos do banco de dados e ao mesmo tempo preocupar-se com regras de negcio da aplicao. Alm disso, o cdigo SQL validado somente em tempo de execuo, aumentando a possibilidade de bugs. O sistema pode ser organizado em camadas para separar os diferentes detalhes de implementao. Uma delas seria a camada de persistncia, que se encarregaria de resolver todos os problemas relativos gerao de SQL, conexo com o banco e detalhes especficos do SGBD. As responsabilidades desta camada podem ser delegadas a um framework. Frente a isso, o presente trabalho prope o desenvolvimento de um Object Persistence Framework (OPF) que utilize a tcnica de Object-Relational Mapping (ORM). Com a sua utilizao, o programador ser poupado da tarefa de implementar comandos em SQL para ler e gravar informaes no banco de dados. O framework ser voltado para o desenvolvimento de sistemas orientados a objetos em Delphi para Windows, linguagem e plataforma nas quais ser implementado. Esta escolha foi tomada tendo em vista que a linguagem de maior domnio do autor h anos, conhecendo tambm empresas da regio de Blumenau que a utilizam. Para justificar a relevncia desta linguagem, Tiobe Software (2010) aponta Delphi entre as dez linguagens mais populares no ano de 2010.

Um framework um conjunto de classes cooperantes que constroem um projeto reutilizvel para uma determinada categoria de software. (GAMMA et al., 2000, p. 41).

17 1.1 OBJETIVOS DO TRABALHO

O objetivo deste trabalho desenvolver um OPF em Delphi que utilize a tcnica de ORM para fornecer a camada de persistncia a uma aplicao. Os objetivos especficos do trabalho so: a) definir um modelo de anotao especfica para o ORM em Delphi; b) implementar os componentes que iro compor o motor de persistncia, que ser responsvel por gerar comandos select, insert, update e delete na linguagem SQL e execut-los para ler ou gravar objetos de entidades no banco de dados; c) implementar os componentes que iro compor a infraestrutura de manipulao dos objetos de entidades na aplicao, controlando o seu ciclo de vida. Tais componentes devero permitir manter o cache dos objetos em memria local para otimizao de desempenho; d) fazer com que o framework suporte alguns SGBDs de mercado, a saber, os SGBDs MySQL e Firebird.

1.2

ESTRUTURA DO TRABALHO

O trabalho divide-se em quatro captulos. No segundo captulo apresentada a fundamentao terica necessria para o entendimento do trabalho, onde so mencionadas as principais caractersticas de um framework de mapeamento objeto-relacional, tambm os conceitos, tcnicas e padres de projeto que podem ser utilizados no seu desenvolvimento. Tambm nesse captulo, em trabalhos correlatos, sero apresentados dois frameworks de mercado com funcionalidades semelhantes ao framework desenvolvido neste trabalho e tambm uma ferramenta desenvolvida em trabalho de concluso de curso relacionada com o tema. No terceiro captulo ser exposto o desenvolvimento do framework. Nesse captulo so listados os requisitos que o mesmo se prope a atender e a especificao do trabalho, bem como os detalhes de implementao e utilizao de padres. Por fim, no quarto captulo so mostradas as concluses e as extenses sugeridas para trabalhos futuros.

18 2 FUNDAMENTAO TERICA

Neste captulo apresentada a fundamentao terica que foi tomada como base para o desenvolvimento deste trabalho, para que se possa entender como o framework foi desenvolvido. Em primeiro lugar ser comentado qual o papel de um framework. Em seguida ser apresentada a tcnica de mapeamento objeto-relacional, explicando algumas diferenas entre o paradigma da orientao a objetos e o paradigma relacional. Logo aps, sero abordados alguns recursos da linguagem Delphi que foram utilizados, como RunTime Type Information (RTTI) e Atributos Customizados. Tambm ser abordado o conceito de Tipos Anulveis, recurso que foi implementado como parte do desenvolvimento deste trabalho para ser utilizado nas classes de entidades mapeadas. Em seguida, sero apresentados todos os padres de projeto que foram utilizados no desenvolvimento do framework. Ao final, sero apresentados os trabalhos correlatos e suas caractersticas.

2.1

O PAPEL DO FRAMEWORK

Gamma et al. (2000, p. 41-42) esclarece que o framework dita a arquitetura de uma aplicao. o framework que define sua estrutura geral, sua diviso em classes e objetos e em conseqncia as responsabilidades-chave das classes e objetos, como estas colaboram, e o fluxo de controle. Um framework predefine estes parmetros de projeto, de maneira que o projetista ou programador da aplicao possa concentrar-se nos aspectos especficos da aplicao. Um framework disponibiliza um conjunto de componentes ou classes para serem utilizadas ou estendidas por uma aplicao. Neste ltimo caso, o framework customizado para uma aplicao especfica atravs da criao de subclasses para a aplicao, derivadas das classes abstratas do framework. Ao fazer isso, o programador reutiliza o corpo principal e escreve o cdigo que este chama, escrevendo operaes com nomes e convenes de chamada j especificadas. Isso reduz as decises de projeto que ser preciso tomar. Como resultado, possvel no somente construir aplicaes mais rapidamente, como tambm constru-las em estruturas similares. Tais aplicaes sero mais fceis de manter e parecem mais consistentes para seus usurios. Por outro lado, perde-se alguma liberdade criativa, uma vez que muitas

19 decises de projeto j tero sido tomadas (GAMMA et al., 2000, p. 41-42).

2.2

MAPEAMENTO OBJETO-RELACIONAL

Bernardi (2006, p. 46-51) explica que apesar de o paradigma orientado a objetos estar sendo cada vez mais difundido no processo de desenvolvimento de software, no existem hoje solues comerciais robustas e amplamente aceitas neste paradigma para a persistncia de dados. Com o surgimento de bancos de dados ps-relacionais, orientados a objetos e outras alternativas de persistncia de objetos, este cenrio pode mudar, mas atualmente o mercado de aplicaes comerciais ainda dominado pelos SGBDs relacionais. Segundo Fowler (2006, p. 170), no existe um encaixe perfeito entre os dois paradigmas. Objetos e bancos de dados relacionais utilizam mecanismos diferentes para estruturar os dados. Muitas partes integrantes de um objeto, tais como colees e herana, no esto presentes em bancos de dados relacionais. Alm disso, enquanto a orientao a objetos baseada em princpios da engenharia de software onde os objetos so abstraes do mundo real, o paradigma relacional baseado em princpios matemticos, onde as informaes de uma base de dados so consideradas relaes matemticas e esto representadas de maneira uniforme com o uso de tabelas bidimensionais. Quando se cria um modelo de objetos com muita lgica de negcio, o uso de um mecanismo de ORM valioso para melhor organizar os dados e o comportamento associado. O mapeador de dados uma camada de software que separa os objetos na memria do banco de dados. Sua responsabilidade transferir dados entre os dois e tambm isol-los um do outro. (FOWLER, 2006, p. 170). Com o mapeador de dados, os objetos na memria no precisam nem mesmo saber que existe um banco de dados. Eles no precisam conter comandos SQL e certamente no precisam ter nenhum conhecimento do esquema do banco de dados. A Figura 1 mostra como o ORM encaixa-se entre os dois paradigmas.

20

Fonte: adaptado de Bernardi (2006, p. 48).

Figura 1 Encaixe do ORM entre o paradigma relacional e o orientado a objetos

Um framework de persistncia de objetos permite a realizao do armazenamento e manuteno do estado dos objetos em algum meio no-voltil, como um banco de dados, de forma transparente. Uma de suas vantagens que o analista/programador pode trabalhar como se estivesse em um sistema completamente orientado a objetos. Outra vantagem a centralizao do canal de acesso ao SGBD em um s ponto, inacessvel ao programador, tornando a aplicao e o SGBD desacoplveis e dando a possibilidade de troca do SGBD ou alteraes na base de dados sem muito transtorno (BERNARDI, 2006, p. 46-51). Segundo Bernardi (2006, p. 46-51), como regras de mapeamento, pode-se estabelecer uma analogia entre objetos e tabelas, e entre atributos e colunas. Ao se realizar uma contraposio entre os dois modelos importante levar em considerao, com certa flexibilidade, as seguintes regras: a) todas as tabelas devem ter uma chave primria e, no sistema orientado a objetos, cada objeto deve ser nico. Esta unicidade garantida atravs da introduo de um Object IDentifier (OID), que deve ser gerado pelo sistema, no pode ser alterado pelo usurio e no pode depender de outros atributos do objeto; b) os objetos podem possuir atributos simples, que so mapeados para apenas uma coluna, atributos compostos, que so mapeados a outra tabela, e atributos multivalorados, que tambm so mapeados a outra tabela e representam colees, como por exemplo o atributo ListaTelefones de uma classe Cliente; c) a herana entre classes pode ser mapeada de trs formas: criar apenas uma tabela para todas as classes da hierarquia, criar uma tabela para cada classe, ou criar uma tabela para cada classe no-abstrata. Na primeira forma criada uma coluna que identifique, para cada registro da tabela, a classe qual pertence. Nas duas ltimas formas criada nas classes filhas uma coluna que referencie a tabela pai atravs de uma chave estrangeira; d) o mapeamento deve levar em considerao a existncia dos tipos de associaes

21 muitos-para-muitos, muitos-para-muitos com classe de associao, um-paramuitos, um-para-muitos com classe de associao e um-para-um.

2.2.1

Mapeamento de herana

Fowler (2006, p. 283) afirma que como os bancos de dados relacionais no suportam herana segundo os conceitos da orientao a objetos, necessrio mapear a herana para o paradigma relacional. A seguir so explicadas com mais detalhes as trs estratgias de mapeamento de herana para que se possa entend-las com maior clareza.

2.2.1.1

Herana de tabela por classe concreta

Segundo Fowler (2006, p. 283), esta estratgia utiliza uma tabela do banco de dados para cada classe concreta da hierarquia. Cada tabela contm colunas para a classe concreta e todos os seus ancestrais, de modo que qualquer campo na classe pai duplicado pelas tabelas das classes filhas, conforme se pode ver na Figura 2.

Fonte: adaptado de Fowler (2006, p. 283).

Figura 2 Herana de tabela por classe concreta

Fowler (2006, p. 285) afirma que uma das vantagens desta estratgia que cada tabela auto-contida e no possui campos irrelevantes. A conseqncia que estas tabelas faro bastante sentido quando utilizadas por outras aplicaes que no as estejam mapeando para objetos. Alm disso, no h junes a realizar durante a leitura dos dados das classes concretas.

22 Um dos problemas desta estratgia, conforme Fowler (2006, p. 283), garantir que a chave primria seja nica no apenas para uma tabela, mas para todas as tabelas da hierarquia. Isso deve ser feito para que se possa realizar consultas polimrficas que obtm registros de vrias destas tabelas, mas cada objeto tenha um identificador distinto. Por exemplo, uma consulta para retornar um Jogador com id igual a 10. Se forem utilizadas sequences no banco de dados este problema fica mais fcil de resolver, basta utilizar a mesma sequence para gerar as chaves primrias de todas estas tabelas. Fowler (2006, p. 285) ainda explica que um ponto fraco desta estratgia a impossibilidade de forar relacionamentos no banco de dados para classes abstratas. Usando o exemplo citado no diagrama, no seria possvel criar uma chave estrangeira no banco de dados que apontasse para um Jogador. Alguma lgica de negcio orientada a objetos poderia ter esta necessidade. Outro ponto fraco a refatorao nas classes superiores. Cada vez que alterado um campo na classe superior, devem ser alteradas todas as tabelas que contenham este campo. Finalmente, mais uma desvantagem que cada consulta polimrfica geraria consultas em vrias tabelas, levando a mltiplos acessos ao banco de dados. Bauer e King (2007, p. 195) afirmam que este problema pode ser minimizado utilizando unions.

2.2.1.2

Herana de tabela nica

Conforme Bauer e King (2007, p. 199), uma hierarquia inteira de classes pode ser mapeada a uma nica tabela. Esta tabela inclui colunas para todas as properties de todas as classes da hierarquia. A subclasse concreta representada por uma linha particular na tabela que identificada pelo valor presente em uma coluna especial, o discriminador do tipo da classe, conforme a Figura 3.

23

Fonte: adaptado de Fowler (2006, p. 269).

Figura 3 Herana de tabela nica

Segundo Fowler (2006, p. 269), ao mapear para um banco de dados relacional, tenta-se minimizar a quantidade de joins que pode crescer rapidamente ao processar uma estrutura de herana em diversas tabelas. Bauer e King (2007, p. 199) explicam que esta estratgia de mapeamento a vencedora em termos de desempenho e simplicidade. Os dados podem ser obtidos sem joins nem unions complexas. Alm disso, a melhor forma de representar polimorfismo. Tanto consultas polimrficas quanto no-polimrficas funcionam bem. Fowler (2006, p. 270) diz tambm que a refatorao se torna mais fcil quando necessrio mover campos para cima ou para baixo na hierarquia, pois no requer nenhuma alterao no banco de dados. Bauer e King (2007, p. 200) afirmam que a maior desvantagem desta estratgia que as colunas das classes filhas devem ser declaradas como anulveis. Se cada uma das classes filhas declara vrios campos obrigatrios, a perda das construes de not null pode ser um problema para a integridade dos dados. Fowler (2006, p. 270) tambm aponta outros pontos fracos, como desperdcio de espao no banco de dados se a mesma tabela representar uma grande quantidade de classes e resultar em muitos campos com o valor null. O desempenho do sistema tambm pode ser prejudicado se a tabela for grande demais e precisar de muitos ndices, ou ento problemas relacionados a bloqueios freqentes nesta tabela.

2.2.1.3

Herana de tabela por subclasse

Conforme Bauer e King (2007, p. 203), esta estratgia representa relacionamentos de herana como chaves estrangeiras no banco de dados. Cada classe ou subclasse que declara

24 campos persistentes, incluindo classes abstratas, possui sua prpria tabela. A Figura 4 exemplifica como ficariam as tabelas no banco de dados.

Fonte: adaptado de Bauer e King (2007, p. 204).

Figura 4 Herana de tabela por subclasse

Bauer e King (2007, p. 203) explicam que nesta estratgia, a tabela contm campos apenas para as properties declaradas na prpria classe, pois as properties herdadas j se tornaram campos na tabela que representa a classe pai. Alm disso, nas tabelas filhas, o mesmo campo que representa a chave primria, tambm uma chave estrangeira para a tabela pai. Segundo Bauer e King (2007, p. 204), a principal vantagem desta estratgia que o esquema das tabelas normalizado2. A evoluo do esquema e a integridade das construes so corretas e o modelo relacional fica bem parecido com o modelo das classes. Atende ao mesmo tempo as convenes do paradigma relacional quanto orientado a objetos. Uma associao de uma classe para a classe pai pode ser representada no banco como uma chave estrangeira para a tabela pai e uma associao para a classe filha pode ser representada como uma chave estrangeira para a tabela filha. Fowler (2006, p. 277) tambm afirma que todas as colunas so relevantes para todas as linhas, de modo que as tabelas so mais fceis de compreender e no desperdiam espao. Dentre as desvantagens, segundo Fowler (2006, p. 277), estaria o desempenho das consultas, j que vrias tabelas precisam ser acessadas para carregar um nico objeto. As tabelas das classes superiores podem se tornar um gargalo, pois elas precisam ser acessadas com mais freqncia. Alm disso, quando necessrio refatorar uma classe movendo campos para cima ou para baixo na hierarquia, necessrio alterar mais de uma tabela no banco.
2

Segundo Heuser (2000), normalizao define regras que devem ser obedecidas para que o esquema do banco de dados seja considerado bem projetado. Existe um conjunto numerado de formas normais para verificar tabelas em banco de dados relacionais.

25 2.3 RUNTIME TYPE INFORMATION (RTTI)

Segundo Martins (2003, p. 6-11), RTTI um poderoso recurso do Delphi que permite obter informaes de tipos em tempo de execuo. Os operadores mais bsicos do RTTI so o
is

e o as, que permitem, respectivamente, testar o tipo de um objeto e efetuar uma converso

em tempo de execuo. O RTTI permite extrair informaes mais detalhadas como mtodos e propriedades de um objeto. O prprio Delphi faz uso intensivo de RTTI em vrias partes da sua Integrated Development Environment (IDE), como por exemplo para salvar e carregar dados de arquivos
.dfm3

e tambm nas abas object inspector4 e structure5. Internamente, o RTTI organizado

em tabelas com dados que podem ser teis para o desenvolvedor, tais como informaes sobre classes, mtodos virtuais, dinmicos e interfaces implementadas. Outro recurso interessante a Virtual Method Table (VMT) que pode ser utilizada em conjunto com RTTI para obter informaes mais detalhadas sobre os mtodos, como ponteiros para todos os mtodos virtuais declarados em uma classe e em suas ancestrais, alm de ponteiros para outras tabelas. (MARTINS, 2003, p. 6-11). No Delphi at a verso 2009, as informaes de RTTI esto disponveis apenas para mtodos e properties de uma classe que possuem visibilidade published ou padro. Porm Groves (2009) apresenta o RTTI estendido que surge com o Delphi 2010. Nesta verso do Delphi foi feita uma reviso na construo interna do RTTI, o qual agora permite acessar informaes de atributos, mtodos e properties de qualquer visibilidade. Tambm foi criada uma Application Programming Interface (API) mais facilitada para obteno das informaes. Outro recurso interessante que est disponvel a partir da verso 2010 so os chamados Atributos Customizados. Trata-se de informaes adicionais, customizveis em forma de anotao, que podem ser atribudas a classes, atributos, mtodos e properties em tempo de design para serem posteriormente extradas via RTTI, semelhante ao recurso de annotations da linguagem de programao Java. Todos estes recursos citados esto agora disponveis na linguagem Delphi para plataforma Windows, verso 2010.
3

Os arquivos .dfm no Delphi so arquivos que mantm as informaes dos componentes presentes em cada formulrio. (SASSE, 2005).
4

O object inspector exibe as propriedades e eventos do componente selecionado na tela em modo designer e permite o usurio alterar os valores das propriedades ou atribuir um evento ao objeto (GAJIC, 2006).
5

A aba structure exibe em formato de rvore a hierarquia do cdigo fonte caso o usurio esteja no modo editor de cdigo, ou a hierarquia dos componentes do formulrio caso esteja no modo designer (GAJIC, 2006).

26 Conforme Mouro (2009, p. 104-121), o uso da RTTI est quase sempre ligado a frameworks que venham a ser desenvolvidos para centralizao e otimizao dos sistemas. Esses frameworks tm por objetivo trazer maior flexibilidade a um sistema e produtividade ao desenvolvedor. Um exemplo seria um framework de validao, onde se centraliza na classe a ser validada todo o cdigo responsvel por isso, ao invs de replicar por todo sistema uma regra de negcio. Com nova API do RTTI do Delphi 2010, possvel acessar quais propriedades foram declaradas no objeto que est sendo lido e quais foram herdadas das classes superiores, alm da possibilidade de alterar os valores dos atributos e propriedades dos objetos em tempo de execuo. Esta informao de extrema importncia para implementaes de mapeamento objeto-relacional (MOURO, 2009, p. 104-121).

2.4

ATRIBUTOS CUSTOMIZADOS

Conforme Embarcadero (2010), atributos customizados, ou custom attributes, so um recurso da linguagem de programao Delphi que permite anotar tipos e membros de tipos com objetos especiais que carregam informaes adicionais. Essas informaes podem ser consultadas em tempo de execuo. Os atributos customizados estendem o modelo normal de orientao a objetos com elementos orientados a aspectos. Em geral, atributos customizados so teis para construo de frameworks de propsito geral que analisam tipos estruturados como objetos em tempo de execuo e introduzem um novo comportamento baseado nas informaes adicionais fornecidas pelos atributos anotados. Tais atributos no modificam o comportamento dos tipos ou membros por si ss. O cdigo que os consome precisa consultar especificamente pela existncia dos atributos e tomar as aes apropriadas para aplicar o comportamento desejado (EMBARCADERO, 2010).

2.4.1

Declarao de Atributos Customizados

Embarcadero (2010) afirma que um atributo customizado declarado como uma simples classe. Para declarar o seu prprio atributo customizado, o desenvolvedor precisa

27 declarar uma classe Delphi derivada de uma classe especial chamada TCustomAttribute, localizada na unit System. As restries so que uma classe de atributo customizado no pode ser declarada como classe abstrata e no deve conter nenhum mtodo abstrato. O Quadro 1 mostra um exemplo.
type TMeuAtributo = class(TCustomAttribute) end; Fonte: adaptado de Embarcadero (2010).

Quadro 1 Declarao de Atributos Customizados

Feito isto, a classe TMeuAtributo pode ser utilizada para anotar qualquer tipo, como classes, records ou interfaces. Tambm possvel anotar nos membros de tais tipos, como se pode ver no Quadro 2.
type [TMeuAtributo] TIntegerEspecial = type Integer; TAlgumaClasse = class [TMeuAtributo] procedure FazAlgumaCoisa; end; Fonte: adaptado de Embarcadero (2010).

Quadro 2 Anotaes com Atributos Customizados

Para carregar o atributo customizado com informaes adicionais que possam ser utilizadas em tempo de execuo, necessrio declarar construtores para esta classe, conforme mostrado no Quadro 3.
type TAtributoComConstrutor = class(TCustomAttribute) public constructor Create(const AlgumTexto: string); end; Fonte: adaptado de Embarcadero (2010).

Quadro 3 Construtores em Atributos Customizados

Declarado o construtor, o atributo pode ser utilizado conforme mostrado no Quadro 4.

28

type TAlgumaClasse = class [TAtributoComConstrutor(Texto com informaes.)] procedure FazAlgumaCoisa; end; Fonte: adaptado de Embarcadero (2010).

Quadro 4 Utilizao dos construtores nos Atributos Customizados

Conforme Embarcadero (2010), a execuo de mtodos funciona nos atributos customizados normalmente como outras classes. Isto significa que podem ser definidos vrios construtores sobrecarregados na classe do atributo. Porm, como estes construtores sero resolvidos em tempo de compilao, os parmetros dos construtores necessariamente devem ser valores constantes. No so aceitos parmetros do tipo var ou out.

2.4.2

Extrao de Atributos Customizados

Embarcadero (2010) ainda explica que para extrair em tempo de execuo as informaes que foram anotadas utilizando determinados atributos customizados, o desenvolvedor precisa explicitamente escrever cdigo para consult-las. Para isto utilizada a classe TRTTIContext, localizada na unit RTTI. O Quadro 5 apresenta um exemplo de cdigo fonte para realizar tal consulta.
var LContext: TRttiContext; LType: TRttiType; LAttr: TCustomAttribute; begin { Instancia um novo contexto do RTTI } LContext := TRttiContext.Create { Extrai as informaes de RTTI da classe TAlgumaClasse } LType := LContext.GetType(TAlgumaClasse); { Pesquisa pelo atributo e realiza ao especial } for LAttr in LType.GetAttributes() do if LAttr is TMeuAtributo then Writeln(TMeuAtributo(LAttr).InformacaoAdicional); end; Fonte: adaptado de Embarcadero (2010).

Quadro 5 Extrao de Atributos Customizados

Neste exemplo est sendo considerado que exista na classe TMeuAtributo uma propriedade chamada InformacaoAdicional, que preenchida no construtor desta classe

29 com o valor que foi passado como parmetro no construtor.

2.5

TIPOS ANULVEIS

Conforme MSDN (2006), a estrutura genrica Nullable<T> representa um objeto cujo tipo genrico um tipo primitivo ao qual pode ser atribudo o valor null. Neste caso, T representa o tipo primitivo encapsulado. Um tipo dito como sendo anulvel se a ele pode ser atribudo um valor ou uma referncia nula indicando a ausncia de valor. Conseqentemente, um tipo anulvel pode expressar um valor, ou expressar que nenhum valor existe. Por exemplo, na linguagem C#, um tipo referencivel como String automaticamente anulvel, enquanto um tipo primitivo inteiro de 32 bits no . Um tipo primitivo no pode ser anulvel porque ele possui capacidade suficiente para expressar somente os valores apropriados para tal tipo e no possui capacidade adicional para expressar o valor null (MSDN, 2006). Tipos anulveis so utilizados para representar coisas que podem existir ou no, dependendo da circunstncia. Por exemplo, em uma coluna no-nula de uma tabela de banco de dados, o valor pode existir em uma linha e no existir em outra. Suponha-se que a coluna seja representada como um atributo de uma classe, definido como um tipo primitivo. Neste caso, o atributo poderia conter todos os valores vlidos para tal coluna, mas no poderia acomodar uma informao adicional para indicar que no existe valor. Portanto, o atributo poderia ser declarado utilizando o tipo Nullable<T> ao invs de um tipo primitivo (MSDN, 2006). A estrutura genrica Nullable<T> est disponvel no .Net Framework a partir da verso 2.0 e possui duas propriedades principais: HasValue e Value. Em uma varivel
Nullable<T>,

se a propriedade HasValue for verdadeira, o valor do objeto pode ser acessado

atravs da propriedade Value. Caso contrrio, o valor contido indefinido e qualquer tentativa de acesso propriedade Value dispararia uma exceo (MSDN, 2006).

30 2.6 PADRES DE PROJETO

A seguir so apresentados os padres de projeto que foram utilizados para o desenvolvimento do framework ou que so indicados para serem utilizados juntamente com o framework para o desenvolvimento de sistemas.

2.6.1

Padro Data Access Object (DAO)

Segundo Trottier (2004, p. 294), o padro de projeto DAO prov uma conexo entre a camada de regra de negcios e a camada de persistncia da aplicao de forma transparente. Com isso abstrado e encapsulado todo o acesso fonte de dados, escondendo completamente os detalhes de sua implementao dos componentes de negcio que o utilizam. O DAO pode ser implementado para persistir os dados de vrias formas diferentes, como acesso a um SGBD, arquivos eXtensible Markup Language (XML) ou outros tipos de persistncia, ou at transmitir os dados atravs de Remote Method Invocation (RMI) ou sockets, por exemplo. Enquanto isso, a camada de negcio precisa se preocupar somente com a interface do DAO. Desta forma, assim como a fonte de dados pode mudar, a implementao interna do DAO tambm pode mudar, garantindo que nenhuma alterao necessria no cdigo fonte da camada de negcio que a utiliza.

2.6.2

Padro Identity Field

Segundo Fowler (2006, p. 215), o padro Identity Field, em portugus Campo Identidade, serve para guardar o campo Id de um banco de dados em um objeto para manter a identidade entre o objeto e uma linha do banco de dados. O campo Id, neste caso, representa a chave primria da tabela. A Figura 5 apresenta a aplicao desse padro em uma classe.

31

Fonte: Fowler (2006, p. 215).

Figura 5 Padro Identity Field

Os bancos de dados relacionais diferenciam um registro de outro usando uma chave em particular, a chave primria. Entretanto, objetos na memria no possuem essa tal chave. No h problemas para ler dados de um banco de dados, mas para grav-los de volta, necessrio vincular o banco de dados ao sistema de objetos em memria. Em essncia, o campo de identidade muito simples. Basta armazenar a chave primria da tabela em um atributo dos objetos. Porm, a seguir so apresentadas algumas problemticas que este padro envolve e alternativas para soluo. (FOWLER, 2006, p. 215).

2.6.2.1

Chaves com ou sem significado

Fowler (2006, p. 215) explica que a primeira preocupao se devem ser usadas chaves com ou sem significado. Uma chave com significado como o nmero do Cadastro de Pessoa Fsica (CPF) de um cliente. Uma chave sem significado basicamente um nmero randmico que o banco de dados inventa e que no se destina a uso de seres humanos. O perigo de uma chave com significado que, embora em teoria elas sejam boas chaves, na prtica no o so. Para simplesmente funcionar, as chaves precisam ser nicas. Para funcionar bem, elas precisam ser imutveis. Embora os nmeros atribudos sejam supostamente nicos e imutveis, erros humanos muitas vezes fazem com que eles no sejam nem uma coisa nem outra. Se o usurio de um sistema digitar equivocadamente o nmero do CPF de um cliente no lugar de outro, o registro resultante no nem nico e nem imutvel, presumindo que o usurio queira corrigir o erro. Com isso, chaves com significado so indicadas apenas para sistemas pequenos e casos muitos estveis.

32 2.6.2.2 Chaves simples versus chaves compostas

Conforme Fowler (2006, p. 215), uma chave simples usa apenas um campo do banco de dados. Uma chave composta usa mais de um. A vantagem de uma chave composta que ela freqentemente mais fcil de usar quando uma tabela faz sentido no contexto de outra. Um bom exemplo so os pedidos e as linhas de itens, em que uma boa chave para uma linha do item uma chave composta pelo nmero do pedido e um nmero seqencial que identifica a linha do pedido. Embora freqentemente as chaves compostas faam sentido, as chaves simples so melhores em termos de uniformidade. Se forem utilizadas chaves simples em todo o sistema, pode-se usar o mesmo cdigo para toda manipulao de chaves, enquanto as chaves compostas requerem tratamento especial para cada caso em classes concretas. Para representar chaves compostas, a melhor opo criar uma classe de chave. Uma classe de chave genrica pode armazenar uma seqncia de objetos que atuam como os segmentos da chave.

2.6.2.3

O tipo da chave

O tipo do campo que guarda a chave outra questo importante. A operao mais comum que feita com uma chave o teste de igualdade, portanto o ideal utilizar um tipo com operao rpida de igualdade. Outra operao importante a obteno da prxima chave. Assim, um tipo de inteiro longo freqentemente a melhor aposta. As strings tambm podem se adequar, mas a verificao da igualdade pode ser mais lenta e incrementar strings um pouco mais difcil de implementar (FOWLER, 2006, p. 216).

2.6.2.4

Obtendo uma nova chave

Segundo Fowler (2006, p. 217), para criar um novo objeto persistente ser necessria uma nova chave. Existem trs opes principais: Deixar o banco de dados ger-la automaticamente, usar um Global Unique IDentifier (GUID) ou gerar a prpria chave na aplicao. Deixar o banco de dados gerar a chave o caminho mais fcil, desde que o banco

33 tenha esta funcionalidade. Se for utilizado um campo auto-gerado, cada vez que inserido um registro no banco de dados, este gera uma chave primria nica automaticamente. Porm, nem todos os bancos de dados fazem isto da mesma maneira. Muitos dos que fazem lidam com isso de um modo que causa problemas para o mapeamento objeto-relacional, por exemplo, se no existir uma maneira de resgatar o valor que foi gerado para a chave (FOWLER, 2006, p. 217). Uma abordagem alternativa gerao automtica so as chamadas sequences, ou seqncias, onde envia-se um comando select que referencia a seqncia e banco de dados ento retorna o prximo valor gerado. A pesquisa da seqncia automaticamente executada em uma transao separada, de forma que no bloquear transaes concorrentes. O seu nico ponto negativo que tambm no est disponvel em todos os bancos de dados (FOWLER, 2006, p. 217). Um GUID um nmero gerado que idealmente nico em todas as mquinas no espao e no tempo. Algumas plataformas fornecem funes para gerao do GUID, como a API do Windows. O algoritmo interessante e envolve endereos de placa ethernet, hora do dia, nano segundos e nmeros de identificao dos chips. Sendo um nmero completamente nico, considera-se uma chave segura. Uma desvantagem do GUID que a chave resultante possui 128 bits representados em 32 caracteres, e isso pode ser um problema pois chaves longas so difceis tanto de digitar quanto de ler. Por seu tamanho extenso, elas tambm podem levar a problemas de desempenho, especialmente com ndices (FOWLER, 2006, p. 217). A ltima opo gerar a prpria chave. Um mecanismo simples para sistemas pequenos fazer uma varredura de tabela usando a funo SQL max para encontrar a maior chave na tabela e ento increment-la de uma unidade para us-la. Infelizmente essa leitura bloqueia a tabela interna enquanto estiver sendo executada, o que significa que seu desempenho ser diminudo quando houver inseres concorrentes. Tambm necessrio assegurar-se de que h um completo isolamento entre as transaes, seno diferentes transaes podem obter o mesmo valor de Id. Outra abordagem usar uma tabela de chaves separada. Esta tabela tipicamente ter uma linha para cada tabela no banco de dados e possui duas colunas: nome e prximo valor disponvel. Para usar esta tabela de chave, l-se determinada linha, guarda-se o nmero, incrementa-se o nmero e grava-se o nmero de volta na linha (FOWLER, 2006, p. 218).

34 2.6.2.5 Trabalhando com herana

Quando se utiliza herana necessrio um cuidado especial. Se estiver sendo utilizada a estratgia de herana de tabela concreta ou herana de tabela de classe, deve-se mapear chaves que sejam nicas na hierarquia em vez de nicas em cada tabela. Isto deve ser feito para que no existam dois objetos com mesmo valor de identidade que so convertveis para a classe pai, o que estaria violando a regra da unicidade. Para ter este comportamento, declarase o campo que contm o Id na classe pai, que as classes filhas herdaro este campo. A estratgia de gerao do novo valor tambm teria que ser mapeada na classe pai para garantir a unicidade em toda a hierarquia de classes (FOWLER, 2006, p. 216).

2.6.3

Padro Identity Map

Conforme Fowler (2006, p. 196-199), o padro Identity Map, ou Mapa de Identidade, assegura que cada objeto seja carregado apenas uma vez, mantendo cada objeto carregado em um mapa. Procura-se objetos usando o mapa quando se referindo a eles. Se fossem carregados os dados do mesmo registro do banco de dados em dois objetos diferentes, alguns valores poderiam acabar sendo perdidos quando se atualiza ambos os objetos. Relacionado a isso est um problema bvio de desempenho. Se forem carregados os mesmos dados mais de uma vez, haver um custo alto em chamadas remotas. Assim, deixar de carregar os mesmos dados duas vezes no apenas ajuda na consistncia, mas pode tambm aumentar a velocidade da aplicao. Um Mapa de Identidade mantm um registro de todos os objetos que foram lidos do banco de dados em uma nica transao de negcio. Sempre que precisar de um objeto, a aplicao verifica o Mapa de Identidade primeiro para ver se j o tem.

2.6.3.1

Funcionamento do Mapa de Identidade

Fowler (2006, p. 196-199) explica que a idia bsica por trs do Mapa de Identidade ter um mapa ou uma srie de mapas contendo objetos que foram trazidos do banco de dados. Em um caso simples, com um esquema isomrfico, tem-se um mapa por tabela do banco de

35 dados. Quando a aplicao for carregar um objeto do banco de dados, primeiro verifica o mapa. Se houver um objeto nele que corresponda ao que se estiver carregando, utiliza-se este objeto do mapa. Caso contrrio, seleciona-se do banco de dados, colocando os objetos no mapa para referncia futura quando houver necessidade. Geralmente se usa um mapa de identidade para gerenciar qualquer objeto trazido de um banco de dados e modific-lo. A razo principal que no se deseja ter uma situao na qual dois objetos na memria correspondam a um nico registro no banco de dados. Nesta situao, poderiam modificar-se os dois registros inconsistentemente e assim confundir o mapeamento do banco de dados. Outra importncia do Mapa de Identidade que ele atua como um cache para as leituras do banco de dados, o que significa que voc pode evitar ir ao banco de dados cada vez que precisar de algum dado. O Mapa de Identidade ajuda a evitar conflitos de atualizao dentro de uma mesma sesso, mas no faz nada para lidar com conflitos que atravessam vrias sesses (FOWLER, 2006, p. 196-199). A Figura 6 mostra um diagrama de classes exemplificando um mapa de identidade.

Fonte: adaptado de Fowler (2006, p. 196).

Figura 6 Padro Identity Map

Para cada mapa de identidade, existe um campo mapa, representado no diagrama por
objetos,

e mtodos de acesso. A Classe ChaveMapa uma classe interna da classe para ser utilizada como chave para o HashMap. A implementao dos

MapaDeIdentidade,

mtodos adicionarObjeto e lerObjeto em Java ficaria conforme o Quadro 6.

36

public void adicionarObjeto(Object objeto) { String classe = objeto.getClass().getName(); long id = lerIdObjeto(objeto); ChaveMapa chave = new ChaveMapa(classe, id); objetos.put(chave, objeto); } public Object lerObjeto(String classe, long id) { ChaveMapa chave = new ChaveMapa(classe, id); return objetos.get(chave); } Fonte: Fowler (2006, p. 199).

Quadro 6 Implementao de mtodos do Identity Map em Java

O mesmo cdigo fonte em Delphi ficaria conforme o Quadro 7.


procedure TMapaIdentidade.AdicionarObjeto(Objeto: TObject); var Chave: TChaveMapa; begin Chave = TChaveMapa.Create(Objeto.ClassName, LerIdObjeto(Objeto)); Objetos.Put(Chave, Objeto); end; function TMapaIdentidade.LerObjeto(Classe: string; Id: LongInt): TObject; var Chave: TChaveMapa; begin Chave = TChaveMapa.Create(Classe, Id); Result := Objetos.Get(Chave); end; Fonte: adaptado de Fowler (2006, p. 199).

Quadro 7 Implementao de mtodos do Identity Map em Delphi

2.6.4

Padro Strategy

Na concepo de Gamma et al (2000, p. 315-323), o padro Strategy define uma famlia de algoritmos, encapsula cada um deles e torna-os substituveis. Alm disso, permite que o algoritmo varie independente dos clientes que o utilizam. Considere-se um exemplo de ordenao. Existem vrios algoritmos de ordenao, como Quicksort, Bubblesort e Mergesort. Amarrar todos estes algoritmos com as classes que os utilizam no desejvel por algumas razes: a) lgicas de negcio que necessitam de ordenao se tornariam mais complexas se inclussem o cdigo responsvel pela ordenao. Isso tornaria o cdigo de lgica

37 de negcio maior e mais difcil de manter, especialmente se for necessrio suportar diversos algoritmos de ordenao; b) diferentes algoritmos sero apropriados em diferentes momentos. No desejvel suportar diversos algoritmos de ordenao se eles no forem utilizados; c) difcil adicionar novos algoritmos e variar entre os j existentes quando o cdigo de ordenao j est embutido na lgica de negcio. Estes problemas podem ser evitados definindo classes que encapsulam diferentes algoritmos de ordenao. Um algoritmo que encapsulado desta forma chamado de estratgia. A Figura 7 mostra um diagrama de classes exemplificando este padro.

Fonte: adaptado de Gamma et al (2000, p. 316).

Figura 7 Padro Strategy

Gamma et al (2000, p. 315-323) afirma que o padro Strategy pode ser utilizado quando: a) muitas classes afins diferem apenas em seu comportamento. O padro prov uma forma de configurar uma classe com um ou vrios comportamentos; b) so necessrias diferentes variaes de um algoritmo. Por exemplo, podem ser definidos algoritmos que refletem diferentes escolhas que podem mudar com o tempo ou espao. Estratgias podem ser utilizadas quando estas variaes so implementadas como uma hierarquia de classes de algoritmos; c) um algoritmo utiliza dados que no deveriam ser conhecidos por quem o utiliza. Usa-se o padro Strategy para evitar a exposio de estruturas complexas especficas do algoritmo; d) uma classe define muitos comportamentos, mtodos complexos com mltiplos comandos condicionais.

38 2.6.5 Padro Singleton

Conforme Gamma et al (2000, p. 127-134), para certas classes importante haver somente uma instncia. Exemplos para tais casos seriam uma classe de spooler de impresso, uma classe de sistema de arquivos ou uma classe de gerenciador de janelas. O padro Singleton serve para garantir que uma classe possua apenas uma instncia, e prov um ponto global de acesso a ela. Uma varivel global faz um nico objeto ser facilmente acessvel, mas no garante que objetos da mesma classe possam ser instanciados em outros locais do sistema. Uma soluo mais inteligente tornar a prpria classe responsvel por manter o ciclo de vida da sua prpria instncia. Uma classe pode interceptar requisies de criao de novos objetos para garantir que outras instncias no sejam criadas, e tambm pode disponibilizar um mtodo principal para acessar esta instncia. Aplica-se o padro Singleton em uma classe fazendo a classe atender s seguintes regras: a) a classe deve possuir um atributo privado e esttico cujo tipo a prpria classe e cujo contedo inicial null. Este atributo ir armazenar a nica instncia da classe. Um nome sugerido para este atributo instance; b) a classe deve possuir um mtodo esttico e pblico por onde tal instncia acessada, cujo tipo do retorno a prpria classe. Tal mtodo dever retornar o contedo do atributo instance. Porm, antes de retornar, faz a seguinte operao: caso o atributo esteja nulo, instancia-o; c) a classe deve garantir que no existe nenhum construtor pblico. Para fazer isto, em alguns casos, necessrio tornar todos os construtores privados; d) em linguagens que no possuem garbage colector, a classe deve garantir a destruio da instncia nica no momento apropriado, como por exemplo, na finalizao do programa. A Figura 8 mostra um diagrama de classes exemplificando este padro.

39

Fonte: Gamma et al (2000, p. 130).

Figura 8 Padro Singleton

Gamma et al (2000, p. 127-134) explica que a aplicao do padro Singleton traz os seguintes benefcios: a) acesso controlado nica instncia: como a classe passa a encapsular tal instncia, ela pode ter um controle rgido sobre como e quando os clientes a acessam; b) escopo reduzido: o padro Singleton uma evoluo sobre as antigas variveis globais. Ele evita que o escopo seja poludo com variveis globais que guardam apenas um objeto; c) pode ser refinado e suportar herana facilmente. Caso seja necessrio controlar uma instncia para cada classe filha, isto pode ser feito com uma lista privada esttica na classe pai, para guardar o registro das classes filhas, no lugar do atributo padro instance; d) caso seja necessrio para a aplicao, pode permitir um nmero varivel de instncias. E isto pode ser feito alterando somente o cdigo fonte da classe
Singleton,

modificando a implementao do mtodo de acesso instncia e o

atributo onde guardado. No necessrio alterar o cdigo cliente. Uma utilidade para isto seria a criao de um pool de objetos; e) maior flexibilidade sobre mtodos estticos: Uma alternativa para o padro Singleton seria a definio de classes com todos os atributos e mtodos estticos, porm esta abordagem torna mais trabalhosa a refatorao caso a classe deva suportar mais de uma instncia. Alm disso, em algumas linguagens os mtodos estticos no podem ser virtuais, ento no podem ser sobrescritos mtodos em classes filhas. Outra vantagem que uma classe Singleton pode ser implementada de tal forma a ser instanciada somente no momento da sua primeira utilizao, e isto pode ser importante para, por exemplo, evitar alocao de memria desnecessariamente.

40 2.6.6 Padro Adapter

Gamma et al (2000, p. 139-150) explica que o padro Adapter, tambm chamado de Wrapper, converte a interface de uma classe em uma outra interface esperada pelo cliente. Este padro permite que certas classes que no podem trabalhar juntas por motivos de incompatibilidade entre interfaces, possam trabalhar em conjunto. Algumas vezes uma classe de elementos grficos que foi implementada para reuso no pode ser reusada porque sua interface no combina com a interface especfica do domnio da aplicao. Considere-se como exemplo um editor de desenho que permite ao usurio desenhar e arranjar elementos grficos como linhas, polgonos e texto em figuras e diagramas. O ponto chave da abstrao do editor grfico o objeto grfico, que possui uma forma editvel e pode desenhar a si mesmo. A interface para objetos grficos definida por uma classe abstrata chamada Forma. O editor define uma classe filha de Forma para cada tipo de objeto grfico: classes Linha, Polgono, Texto e assim por diante (GAMMA et al, 2000, p. 139-150). As classes de formas geomtricas elementares como Linha e Polgono so mais fceis de implementar, mas a classe filha Texto pode ser mais difcil de implementar por ter de tratar de exibio e edio de textos, o que envolve atualizaes de tela mais complexas e gerenciamento de buffer. Entretanto, uma biblioteca pode disponibilizar uma classe sofisticada TextView para exibio e edio de texto. A melhor idia seria reutilizar a classe
TextView

para implementao da classe Texto, porm a implementao dessa biblioteca no

contava com a classe Forma. Ento no possvel utilizar objetos de TextView no lugar de um objeto Forma (GAMMA et al, 2000, p. 139-150). Para fazer com que a classe TextView possa ser utilizada como Forma, poderia ser alterada a classe TextView para ficar conforme a interface da classe Forma, mas isto no possvel a menos que se tenha o cdigo fonte da biblioteca em questo. E mesmo que se tenha no faria sentido mudar a classe TextView. Uma biblioteca no precisa adotar interfaces especficas do domnio da aplicao para funcionar. Ao invs disto, a classe Texto poderia ser definida como uma adaptao da classe TextView para a interface de Forma. Isto pode ser feito de duas formas: a) herdando a interface de Forma e implementao de TextView; b) acomodando uma instncia de TextView dentro de um objeto de Texto e implementando a classe Texto sobre a interface de TextView.

41 Gamma et al (2000, p. 139-150) afirma que estas duas abordagens correspondem respectivamente a duas verses do padro Adapter: adaptador por classe e adaptador por objeto. O diagrama da Figura 9 ilustra o caso do adaptador por objeto.

Fonte: Gamma et al. (2000, p. 140).

Figura 9 Padro Adapter por objeto

Este diagrama mostra como requisies de limites, declaradas na classe Forma, so convertidas para chamadas do mtodo getDimensao() definido na TextView. Desta forma, o editor grfico pode reutilizar a classe TextView normalmente. Freqentemente o adaptador responsvel por funcionalidades que a classe adaptada no fornece. O diagrama mostra como o adaptador pode cumprir esta responsabilidade. O usurio pode arrastar qualquer objeto de
Forma

para uma nova posio da tela, mas a classe TextView no foi desenhada para suportar

isto. A classe Texto pode adicionar esta funcionalidade faltante implementando o mtodo
criaManipulador(),

que retorna uma instncia de uma classe apropriada de Manipulador

(GAMMA et al., 2000, p. 139-150).


Manipulador

uma classe abstrata para objetos que sabem como animar uma Forma

em resposta interao com o usurio, como arrastar uma forma para uma nova posio. Pode haver diferentes classes de Manipulador para diferentes formas. ManipuladorDeTexto, por exemplo, seria a classe correspondente para a classe Texto. Ao retornar uma instncia de
ManipuladorDeTexto,

a classe Texto implementa a funcionalidade que a classe TextView

no possui mas a classe Forma requer. Um adaptador por classe pode ser implementado como uma generalizao de duas classes em uma linguagem que suporta herana mltipla, ou uma generalizao de uma classe

42 que implementa uma determinada interface em linguagens que no suportam herana mltipla. A Figura 10 ilustra um exemplo (GAMMA et al., 2000, p. 139-150).

Fonte: Gamma et al (2000, p. 143).

Figura 10 Padro Adapter por classe

2.6.7

Padro Foreign Key Mapping

Segundo Fowler (2006, p. 233-243), o padro de projeto Foreign Key Mapping, ou Mapeamento de Chave Estrangeira, serve para mapear uma associao entre objetos para uma referncia de chave estrangeira entre tabelas no banco de dados. A Figura 11 exemplifica este padro, onde se mostra as classes acima e as tabelas abaixo.

Fonte: Fowler (2006, p. 233).

Figura 11 Padro Foreign Key Mapping

Os objetos podem se referir uns aos outros diretamente por meio de referncias.

43 Mesmo o sistema orientado a objetos mais simples conter um pequeno grupo de objetos conectados entre si. Para gravar esses objetos em um banco de dados, vital gravar essas referncias. Contudo, j que os dados das referncias em si so explcitos instncia particular do programa sendo executado, no se pode simplesmente gravar os valores de dados em estado bruto. Outra complicao o fato de que os objetos podem facilmente possuir colees de referncias para outros objetos, conforme exemplificado na Figura 12. Tal estrutura viola a primeira forma normal dos bancos de dados relacionais (FOWLER, 2006, p. 233-243).

Fonte: Fowler (2006, p. 234).

Figura 12 Padro Foreign Key Mapping com colees

Um Mapeamento de Chave Estrangeira mapeia uma referncia a um objeto como uma chave estrangeira no banco de dados. A chave bvia para resolver esse problema o campo Id. Cada objeto contm a chave do banco de dados da tabela apropriada. Se dois objetos so conectados com uma associao, esta associao pode ser substituda por uma chave estrangeira no banco de dados. Explicando de forma mais simples, quando for salvar um lbum no banco de dados, grava-se o Id do artista ao qual o lbum est associado no registro do lbum (FOWLER, 2006, p. 233-243).

2.6.7.1

Mapeamento de colees

Fowler (2006, p. 233-243) explica que um caso mais complicado surge quando se tem uma coleo de objetos. No possvel gravar uma coleo no banco de dados, ento necessrio inverter a direo da referncia. Assim, quando existe uma coleo de faixas no lbum, coloca-se a chave estrangeira do lbum no registro da faixa. Alm disso, necessrio

44 tratar atualizaes. Atualizaes significam que faixas podem ser acrescentadas ou removidas da coleo do lbum. Para tratar quais alteraes aplicar no banco de dados, basicamente podem ser utilizadas trs estratgias: excluir e inserir, adicionar um ponteiro reverso ou diferenciar a coleo. Com a excluso e a insero, devem-se excluir todas as faixas do banco de dados vinculadas ao lbum e ento inserir todas as que esto atualmente no lbum. primeira vista essa estratgia parece um tanto espantosa, especialmente se no tiver sido alterada nenhuma faixa. Contudo, a lgica fcil de implementar e, como tal, funciona muito bem comparada com as alternativas. A desvantagem que isso s pode ser feito se as faixas forem mapeamentos dependentes, o que significa que elas devem pertencer ao lbum e no podem ser referenciadas de fora dele (FOWLER, 2006, p. 233-243). Adicionar um ponteiro reverso coloca um vnculo da faixa de volta para o lbum, efetivamente tornando a associao bidirecional. Isso altera o modelo de objetos, mas, por outro lado, pode-se tratar a atualizao usando a tcnica simples para campos univalorados. Se nenhuma dessas opes for atrativa, pode-se fazer uma diferenciao. Existem duas possibilidades: diferenciar em relao ao estado corrente do banco de dados ou diferenciar em relao ao que foi lido na primeira vez. Diferenciar em relao ao banco de dados envolve reler a coleo do banco de dados e ento compar-la com a coleo no lbum. Qualquer coisa no banco de dados que no estiver no lbum obviamente foi removida. Qualquer coisa no lbum que no estiver no disco obviamente um novo item a ser acrescentado (FOWLER, 2006, p. 233-243). Diferenciar em relao ao que foi lido na primeira vez significa que se deve guardar os objetos lidos. Isso melhor j que evita outra leitura do banco de dados. No caso geral, qualquer coisa que tenha sido adicionada coleo precisa ser primeiro verificada para ver se um objeto novo. Isso pode ser feito verificando se ele tem uma chave. Se no tiver, ele precisa ser adicionado ao banco de dados. Para a remoo, deve-se descobrir se a faixa foi movida para outro lbum, se ela no tem um lbum ou se foi completamente excluda. Se ela tiver sido movida para outro lbum, ela deve ser atualizada quando for atualizado esse outro lbum. Se ela no tiver um lbum, necessrio colocar um null na chave estrangeira. Se a faixa foi excluda, ento ela deve ser apagada. Tratar excluses muito mais fcil se o vnculo reverso for obrigatrio, como aqui, onde toda faixa deve estar em um lbum. Dessa maneira, no necessrio preocupar-se em detectar itens removidos da coleo, j que eles sero atualizados quando for processado o lbum ao qual eles foram adicionados (FOWLER, 2006, p. 233-243).

45 Se esse vnculo for imutvel, significando que no pode ser alterado o lbum de uma faixa, ento a adio sempre significa insero, e a remoo sempre significa excluso. Isso torna as coisas ainda mais simples.

2.6.7.2

Tratamento de ciclos

Uma das coisas com que se deve tomar cuidado a existncia de ciclos nas associaes. Digamos que seja necessrio carregar um pedido que tem uma associao com um cliente. O cliente tem um conjunto de pagamentos, e cada pagamento tem pedidos os quais ele est pagando, o que poderia incluir o pedido original que est sendo carregado. Para evitar se perder em ciclos existem duas escolhas que, no final das contas, resumem-se forma como so criados os objetos. Normalmente, uma boa idia para um mtodo de criao incluir dados que lhe daro um objeto completamente formado. Se isso for feito, necessrio colocar a Carga Tardia, mencionada no item 2.6.8, em pontos apropriados para quebrar os ciclos (FOWLER, 2006, p. 233-243). A outra escolha criar objetos vazios e imediatamente coloc-los em um Mapa de Identidade. Dessa maneira, quando o ciclo voltar ao incio, o objeto j estar carregado e o ciclo terminar. Os objetos que so criados no esto completamente formados, mas deveriam estar ao final do procedimento de carga. Isso evita ter que tomar decises em casos especiais sobre o uso de Carga Tardia apenas para fazer uma carga correta.

2.6.7.3

Onde no utilizar

Fowler (2006, p. 233-243) afirma que um Mapeamento de Chave Estrangeira pode ser usado para quase todas as associaes entre classes. Porm no possvel us-lo em associaes muitos-para-muitos. As chaves estrangeiras so valores nicos, e a primeira forma normal diz que no se pode armazenar diversas chaves estrangeiras em um nico campo.

46 2.6.8 Padro Lazy Load

Fowler (2006, p. 200-213) explica que o padro Lazy Load, ou Carga Tardia, define um objeto que no contm todos os dados dos quais precisa, mas sabe como obt-los. O diagrama de seqncia da Figura 13 mostra uma viso geral do funcionamento desse padro.

Fonte: adaptado de Fowler (2006, p. 200).

Figura 13 Padro Lazy Load

Para carregar dados de um banco de dados para a memria, conveniente projetar um sistema de modo que quando carregado um objeto de interesse tambm sejam carregados os objetos relacionados a ele. Isso torna a carga mais fcil para o desenvolvedor que estiver usando o objeto, que de outra forma teria que carregar explicitamente todos os objetos de que precisa. Todavia, se esta premissa for levada ao seu final, chegar ao ponto em que carregar um objeto pode ter o mesmo efeito de carregar toda a base de dados de uma s vez, algo que prejudicaria o desempenho do sistema quando apenas alguns dos objetos so realmente necessrios (FOWLER, 2006, p. 200-213). Uma carga tardia interrompe este processo de carga por um tempo, deixando um marcador na estrutura do objeto de modo que se os dados forem necessrios podem ser carregados apenas quando forem usados. Caso tais dados por algum motivo no sejam

47 utilizados, eles nem mesmo sero carregados. Fowler (2006, p. 200-213) diz que h cinco estratgias principais pelas quais pode ser implementada a carga tardia: inicializao tardia, proxy virtual, armazenador de valor, fantasma ou utilizao de programao orientada a aspectos. A seguir so detalhadas estas estratgias e comentado sobre como escolher a estratgia mais apropriada para cada caso.

2.6.8.1

Inicializao tardia

Inicializao tardia a abordagem mais simples. A idia bsica que cada acesso ao campo verifique primeiro para ver se ele nulo. Se for, calcula-se o valor do campo antes de retorn-lo. Para que isto funcione bem, deve-se assegurar que o campo seja encapsulado, o que quer dizer que todo acesso ao campo, mesmo de dentro da classe, feito por meio de um mtodo de leitura. Usar inicializao tardia simples, mas tende a forar uma dependncia entre o objeto e o banco de dados (FOWLER, 2006, p. 200-213).

2.6.8.2

Proxy virtual

Um proxy virtual um objeto que parece com o objeto que deveria estar no campo, mas na verdade no contm nada. Apenas quando um dos seus mtodos chamado, ele carrega o objeto correto a partir do banco de dados. A vantagem do proxy virtual que ele parece exatamente com o objeto que deve estar l. A desvantagem que ele no este objeto, o que pode resultar num problema de identidade. Alm disso, pode-se ter mais de um proxy virtual para o mesmo objeto real. Todos esses proxies tero diferentes identidades de objeto, mas ainda assim representam o mesmo objeto conceitual (FOWLER, 2006, p. 200-213). Em alguns ambientes, outro problema a necessidade de se criar muitos proxies virtuais, um para cada classe que estiver usando proxy. Isso pode ser evitado em linguagens tipadas dinamicamente, mas em linguagens tipadas estaticamente este trabalho mais difcil. Mesmo quando a plataforma fornece recursos convenientes, como os proxies de Java, outros obstculos podem aparecer.

48 2.6.8.3 Armazenador de valor

Com classes do domnio, pode-se contornar esses problemas usando um armazenador de valor. Conceitualmente, trata-se de um objeto que encapsula algum outro objeto. Para obter o objeto subjacente, solicita-se seu valor ao armazenador de valor, mas apenas no primeiro acesso ele obtm os dados do banco de dados. As desvantagens do armazenador de valor so que a classe precisa saber que ele existe e que se perde a caracterstica explcita da forte verificao de tipos. Pode-se evitar problemas de identidade assegurando que o armazenador de valor nunca seja passado para alm da classe a qual ele pertence (FOWLER, 2006, p. 200213).

2.6.8.4

Fantasma

Um fantasma o objeto real em um estado parcial. Quando carregado o objeto do banco de dados, ele contm apenas seu Id. Sempre que for acessado um campo, ele carrega seu estado completo. claro que no h necessidade de carregar todos os dados de uma vez s. Pode-se reuni-los em grupos que sejam comumente usados juntos. Ao usar um fantasma, pode-se inseri-lo imediatamente no mapa de identidade. Dessa forma mantida a identidade e so evitados todos os problemas causados por referncias cclicas durante a leitura de dados (FOWLER, 2006, p. 200-213).

2.6.8.5

Programao orientada a aspectos

A Carga Tardia uma boa candidata programao orientada a aspectos6. Pode-se colocar o comportamento da Carga Tardia em um aspecto separado, o que permite alterar a estratgia de carga tardia separadamente assim como liberar os desenvolvedores do domnio de ter que lidar com questes de carga tardia (FOWLER, 2006, p. 200-213).

Segundo Soares e Borba (2002), programao orientada a aspectos um paradigma de programao que permite que a implementao de um sistema seja separada em requisitos funcionais e no funcionais, separando cdigo de funes especficas como, por exemplo, controle de concorrncia, tratamento de excees e log.

49 2.6.8.6 Escolhendo a melhor estratgia

Muitas vezes existem situaes nas quais diferentes casos de uso funcionam melhor com diferentes variedades de Carga Tardia, ou ento, casos onde melhor no utiliz-la. A maneira de lidar com isso ter diferentes objetos de interao com o banco para os diferentes casos de uso. Assim, pode-se ter dois objetos mapeadores de pedidos: um que carrega os itens imediatamente e outro que os carrega tardiamente. O cdigo da aplicao escolhe o mapeador apropriado dependendo do caso de uso. Uma variao disso ter o mesmo objeto carregador bsico, mas delegar para um objeto estratgia a deciso sobre o padro de carga. Isto um pouco mais sofisticado, mas pode ser uma maneira melhor de fatorar comportamento (FOWLER, 2006, p. 200-213). A deciso de quando usar a Carga Tardia relacionada quantidade de informao que se deseja trazer do banco de dados quando se carrega um objeto e quantas chamadas ao banco de dados isso ir requerer. Normalmente no faz sentido usar a Carga Tardia em um campo que armazenado na mesma linha do resto do objeto, porque na maioria das vezes no custa mais trazer dados adicionais em uma chamada, mesmo se o campo for grande como um Binary Large OBject (BLOB). S vale a pena considerar Carga Tardia se o campo requer uma chamada de banco de dados extra para ser acessado (FOWLER, 2006, p. 200-213). Muitas vezes, uma boa idia trazer todos os dados que sero necessrios em uma nica chamada, de forma a ter logo todo o grafo de objetos carregado, especialmente se isso corresponder a uma nica interao com uma interface grfica com o usurio. O melhor momento para usar a Carga Tardia quando ela envolver uma chamada extra, e os dados que estiverem sendo requisitados no forem usados quando o objeto principal for usado.

2.6.9

Padro Model View Controller (MVC)

Conforme Quicoli (2007, p. 26-34), o padro de projeto MVC separa a aplicao em trs camadas distintas, model, view e controller, que podem ser definidas da seguinte forma: a) model a representao da informao que a aplicao utiliza. Em um sistema orientado a objetos o model pode ser composto pelas classes de entidades do sistema, como por exemplo classes Pessoa, Cliente e NotaFiscal; b) view a apresentao grfica do model. Por exemplo, um formulrio expondo as

50 informaes de um cliente. Uma view est sempre ligada a um model e sabe como exibi-lo ao usurio. Para um determinado model podem existir vrias views. Alm disso, uma view tambm pode ser composta por vrias views; c) controller responsvel por mapear as aes do usurio em aes do sistema, por exemplo se um boto ou item do menu clicado ele que deve definir como a aplicao responder. A vantagem da separao da aplicao nestas trs camadas torn-las independentes e desacoplveis, alm de possibilitar a reutilizao do mesmo model em vrias views. A Figura 14 mostra como feita a comunicao entre as trs camadas do MVC, na qual as linhas contnuas representam mtodos e as linhas pontilhadas representam eventos.

Fonte: Quicoli (2007, p. 26-34).

Figura 14 A comunicao dentro do MVC

2.7

TRABALHOS CORRELATOS

Verificou-se que j foram elaborados projetos envolvendo ORM em diversas linguagens de programao. Dentre os pesquisados, alguns frameworks sero utilizados como base para este trabalho, os quais so listados a seguir. Tambm sero obtidas ideias da ferramenta para aplicao do padro DAO em sistemas desenvolvidos em Delphi (SARDAGNA, 2007).

2.7.1

Hibernate

Segundo Silva e Silva (2009, p. 113-114), Hibernate um framework de mapeamento

51 objeto-relacional desenvolvido em Java, atualmente considerado o mais conhecido do mercado. Sua principal funo abstrair a camada de persistncia, economizando esforo e preocupaes referentes a tal tarefa. Possui uma arquitetura fcil de configurar, simplificando bastante a tarefa do desenvolvedor. A partir da verso 3 o Hibernate implementa a especificao Java Persistence API (JPA) atravs do conceito de anotaes, existente na linguagem Java, possibilitando definir o mapeamento diretamente na classe. Conforme Bauer e King (2007, p. 192), o Hibernate suporta os seguintes modos de mapeamento de herana: a) herana de tabela por classe concreta; b) herana de tabela nica; c) herana de tabela por subclasse. Bauer e King (2007, p. 386) apresentam atravs da Figura 15 os possveis estados dos objetos de entidade no Hibernate, indicando o seu ciclo de vida. Na especificao JPA, tais objetos so mantidos pela classe EntityManager, cujos nomes dos mtodos so mostrados em itlico no diagrama. Os mtodos que no aparecem em itlico so os correspondentes das verses anteriores do Hibernate, que no implementavam a especificao JPA.

Fonte: Bauer e King (2007, p. 386).

Figura 15 Estados dos objetos e suas transaes no Hibernate

2.7.2

Instant Objects

Instant Objects (Instant Objects, 2006) um framework para desenvolvimento de sistemas em Delphi que conta com um conjunto de componentes de cdigo fonte aberto. Foi

52 desenvolvido para construir aplicaes orientadas a objetos baseadas em objetos de negcio que podem ser persistidos em uma base de dados. O framework conta com componentes de persistncia de objetos e tambm apresentao dos dados atravs de data-aware controls, que so componentes visuais para exibio dos dados. Ele suporta vrios SGBDs diferentes, tanto orientados a arquivos quanto orientados a SQL, como Firebird, Microsoft SQL Server, IBM DB2, Oracle, InterBase, Informix, Advantage Database Server, ElevateSoft DBISAM, FlashFiler, Nexus DB, MySQL, PostgreSQL e outros.

2.7.3

Ferramenta para aplicao do DAO em sistemas desenvolvidos em Delphi

Sardagna (2007, p. 13) descreve seu software como uma ferramenta para aplicao do padro DAO em um sistema j existente. Seu funcionamento baseia-se em retirar o cdigo SQL do cdigo fonte de negcio da aplicao e coloc-lo de forma organizada em uma camada de persistncia que gerada pela ferramenta, seguindo o padro DAO. Tal ferramenta atua diretamente no cdigo fonte da aplicao, alterando-o para uma estrutura que tenha a camada de persistncia encapsulada no padro de projeto DAO.

53 3 DESENVOLVIMENTO DO FRAMEWORK

Neste captulo explicado como o framework foi desenvolvido. Em primeiro lugar, so detalhados os principais requisitos funcionais e no funcionais que o framework se prope a atender. Em seguida apresentada a especificao, que d uma explicao mais formal sobre o desenvolvimento do framework. Logo aps apresentado o modelo de anotao que foi elaborado para o mapeamento objeto-relacional. ento explicada a implementao do framework, onde so citados quais padres de projetos, tcnicas e ferramentas foram utilizadas. Por fim, descrito como as funcionalidades foram testadas, quais os resultados e como o framework foi documentado.

3.1

REQUISITOS PRINCIPAIS DO PROBLEMA A SER TRABALHADO

O framework proposto dever: a) disponibilizar um modelo de anotao baseada em Atributos Customizados para o mapeamento objeto-relacional que possa ser utilizada na implementao de classes de entidades (Requisito Funcional RF); b) gerar comandos select, insert, update e delete na linguagem SQL a partir das classes e anotaes definidas pelo usurio (RF); c) gerar as tabelas do banco de dados a partir das classes e anotaes definidas pelo usurio (RF); d) disponibilizar uma camada de persistncia que permita criar, obter, salvar e remover objetos de entidades de forma transparente (RF); e) disponibilizar um gerenciador de objetos de entidades que controle o ciclo de vida dos objetos e permita fazer cache de objetos em memria local (RF); f) ser desenvolvido utilizando os padres de projeto DAO, Singleton, Adapter, Strategy, Identity Field, Identity Map, Foreign Key Mapping, Lazy Load e permitir que as aplicaes que o utilizem possam ser desenvolvidas utilizando o padro MVC (Requisito No-Funcional - RNF); g) ser implementado utilizando o ambiente de desenvolvimento Delphi 2010 para Windows (RNF);

54 h) suportar a arquitetura cliente-servidor, na qual vrias instncias da aplicao acessam o mesmo banco de dados (RNF); i) ser compatvel com o sistema operacional Microsoft Windows nas verses XP, Vista e 7 (RNF); j) suportar os SGBDs MySQL e Firebird (RNF).

3.2

ESPECIFICAO

Nesta seo apresentada a especificao do framework utilizando conceitos de orientao a objetos e a Unified Modeling Language (UML). Foi utilizada a ferramenta Enterprise Architect para a modelagem do projeto e a elaborao de diagramas de casos de uso, de classes, de componentes e de seqncia. Em primeiro lugar mostrado o comportamento do framework atravs de um diagrama de casos de uso. Depois apresentada a estrutura do framework, expondo uma viso geral dos componentes nos quais foi dividido com diagrama de componentes, e para cada componente uma viso das principais classes que o compe atravs de diagrama de classes. Por fim apresentada a interao entre algumas classes do framework com o diagrama de seqncia.

3.2.1

Comportamento do framework

O framework possui sete casos de uso que so demonstrados na Figura 16. Cada um dos casos de uso ser explicado separadamente, apresentando os cenrios, pr-condies para que possa ser executado e ps-condies que indicam o estado resultante da execuo do caso de uso. Em todos os casos de uso, o nico ator a aplicao.

55

Figura 16 Diagrama de casos de uso

Um caso de uso representa um relato de uso de certa funcionalidade do sistema em questo, sem revelar a estrutura e o comportamento internos desse sistema (MENEZES, 2007, p. 54). A seguir so explicados todos os casos de uso do diagrama. Foram abstrados detalhes como anlise das estratgias de mapeamento, herana, associaes e gerao de SQL, pois so detalhes que a aplicao no precisa se preocupar ao utilizar os casos de uso. O framework disponibiliza estas funcionalidades de forma transparente.

3.2.1.1

UC01 Construir base de dados

O Quadro 8 mostra os detalhes do caso de uso UC01 - Construir base de dados, que a criao das estruturas internas dentro da base de dados, como tabelas, construes e sequences. Considera-se que o elemento base de dados propriamente dito, por exemplo, o arquivo .fdb no caso do Firebird, j esteja criado e configurado no SGBD.

56

UC01 Construir base de dados Pr-condies Classes de entidades mapeadas; gerenciador de base de dados (TDatabaseManager) instanciado; conexo aberta no banco de dados; base de dados instanciada no SGBD. Base de dados criada e pronta para persistncia de objetos. Passos 1. Aplicao invoca o mtodo BuildDatabase do TDatabaseManager; 2. Framework cria todas as tabelas no banco de dados, incluindo campos, chaves primrias e chaves nicas; 3. Framework cria todas as chaves estrangeiras no banco de dados; 4. Framework cria todas as sequences no banco de dados, caso existam sequences mapeadas.
Quadro 8 Caso de uso UC01 Construir base de dados

Ps-condies Cenrio Principal

3.2.1.2

UC02 Persistir objeto de entidade

O Quadro 9 mostra os detalhes do caso de uso UC02 - Persistir objeto de


entidade.

Entenda-se como sendo a gravao de um objeto novo no banco de dados e sua

insero no mapa de objetos persistidos. A partir deste momento, o objeto passa a estar mapeado. Pr-condies Ps-condies Cenrio Principal UC02 Persistir objeto de entidade Classes de entidades mapeadas; base de dados criada; gerenciador de objetos (TObjectManager) instanciado; conexo aberta no banco de dados. Objeto persistido no banco de dados; objeto mapeado no gerenciador de objetos. Passos 1. Aplicao instancia um novo objeto de entidade; 2. Aplicao atribui valores aos atributos ou properties do objeto criado; 3. Aplicao invoca o mtodo Persist do TObjectManager, passando o objeto criado como parmetro; 4. Framework valida o objeto que est sendo persistido; 5. Framework persiste o objeto, inserindo o mesmo no banco de dados; 6. Framework adiciona o objeto no mapa de objetos persistidos. No passo 4, caso o objeto j esteja persistido: 1. Framework gera exceo informando que o objeto j est persistido. No passo 4, caso o objeto j possua o atributo Id preenchido: 1. Framework gera exceo informando que no permitido persistir um objeto com Id j preenchido.

Exceo 1 Exceo 2

Quadro 9 Caso de uso UC02 Persistir objeto de entidade

57 3.2.1.3 UC03 Combinar objeto de entidade

O Quadro 10 mostra os detalhes do caso de uso UC03 - Combinar objeto de


entidade.

Entenda-se como sendo a combinao de um objeto novo que referencia um

registro j gravado no banco de dados, com o valor correspondente j salvo. Considera-se que pode haver outro objeto j mapeado referente ao mesmo registro. Pr-condies UC03 Combinar objeto de entidade Classes de entidades mapeadas; base de dados criada; gerenciador de objetos (TObjectManager) instanciado; conexo aberta no banco de dados; informaes do objeto j persistidas no banco de dados. Objeto atualizado no banco de dados; objeto mapeado no gerenciador de objetos. Passos 1. Aplicao instancia um novo objeto de entidade; 2. Aplicao atribui valores aos atributos ou properties do objeto criado, preenchendo tambm o atributo Id indicando qual objeto deseja-se alterar; 3. Aplicao invoca o mtodo Merge do TObjectManager, passando o objeto criado como parmetro; 4. Framework valida o objeto que est sendo atualizado; 5. Framework aplica update no banco de dados; 6. Framework verifica se j existe um objeto com mesmo Id mapeado; 7. Framework adiciona o objeto no mapa de objetos persistidos; 8. Framework retorna a instncia do objeto atualizado. No passo 6, caso j exista outro objeto com mesmo Id mapeado: 1. Framework copia os valores de todos os atributos do objeto que j estava mapeado para o objeto que foi passado como parmetro para atualizar; 2. Framework retorna a instncia do objeto que j estava mapeado; 3. Aplicao descarta o objeto que foi criado inicialmente e passa a manipular o objeto que foi retornado pelo framework; 4. Finaliza o cenrio principal. No passo 4, caso o objeto j esteja mapeado: 1. Framework gera exceo informando que o objeto j est mapeado. No passo 4, caso o objeto no possua o atributo Id preenchido: 1. Framework gera exceo informando que no permitido atualizar um objeto sem o Id preenchido.

Ps-condies Cenrio Principal

Fluxo alternativo 1

Exceo 1 Exceo 2

Quadro 10 Caso de uso UC03 Combinar objeto de entidade

3.2.1.4

UC04 - Atualizar objeto de entidade persistido

O Quadro 11 mostra os detalhes do caso de uso UC04 - Atualizar objeto de


entidade persistido.

Entenda-se como sendo a gravao dos valores atuais de um objeto

58 j persistido no banco de dados. Pode ser feita com objetos que foram persistidos, combinados ou obtidos. No pode ser feita com objetos novos nem objetos removidos. Pr-condies UC04 Atualizar objeto de entidade persistido Classes de entidades mapeadas; base de dados criada; gerenciador de objetos (TObjectManager) instanciado; conexo aberta no banco de dados; objeto j persistido e mapeado no gerenciador de objetos. Objeto atualizado no banco de dados. Passos 1. Aplicao atribui novos valores aos atributos ou properties de um objeto j persistido e mapeado; 2. Aplicao invoca o mtodo Flush do TObjectManager; 3. Framework detecta os atributos que tiveram valor alterado e executa comando de update no banco de dados para aplicar as alteraes;

Ps-condies Cenrio Principal

Quadro 11 Caso de uso UC04 Atualizar objeto de entidade persistido

3.2.1.5

UC05 Obter objeto de entidade

O Quadro 12 mostra os detalhes do caso de uso UC05 - Obter objeto de


entidade.

Entenda-se como sendo a seleo de um objeto de entidade do banco de dados,

com os respectivos valores armazenados. Aps obtido, o objeto est pronto para ser manipulado pela aplicao, acessando ou alterando os valores de seus atributos. Pr-condies UC05 Obter objeto de entidade Classes de entidades mapeadas; base de dados criada; gerenciador de objetos (TObjectManager) instanciado; conexo aberta no banco de dados; base de dados com informaes cadastradas. Objeto de entidade instanciado e carregado com os valores vindos do banco de dados; objeto mapeado no gerenciador de objetos. Passos 1. Aplicao invoca o mtodo Find do TObjectManager, passando como parmetro a classe e o valor do Id desejado; 2. Framework seleciona o registro do banco de dados correspondente ao Id informado, da tabela que representa a classe informada; 3. Framework instancia um objeto da classe informada e carrega todos os atributos ou properties mapeadas com os valores lidos do banco de dados; 4. Framework adiciona o objeto no mapa de objetos persistidos; 5. Framework retorna o objeto instanciado; 6. Aplicao manipula o objeto retornado. No passo 2, caso a seleo do banco de dados no retorne nenhum registro: 2.1. Framework retorna nil; 2.2. Retorna ao passo 6.
Quadro 12 Caso de uso UC05 Obter objeto de entidade

Ps-condies Cenrio Principal

Exceo 1

59 3.2.1.6 UC06 Obter lista de objetos de entidades

O Quadro 13 mostra os detalhes do caso de uso UC06 - Obter lista de objetos


de entidades.

semelhante ao caso de uso UC05 Obter objeto de entidade, com a UC06 Obter lista de objetos de entidades Classes de entidades mapeadas; base de dados criada; gerenciador de objetos (TObjectManager) instanciado; conexo aberta no banco de dados; base de dados com informaes cadastradas. Objetos de entidade instanciados e carregados com os valores vindos do banco de dados; objetos mapeados no gerenciador de objetos. Passos 1. Aplicao invoca o mtodo FindAll do TObjectManager, passando como parmetro a classe; 2. Framework seleciona os registros do banco de dados, de uma ou mais tabelas que representam a classe informada; 3. Framework instancia vrios objetos da classe informada, um para cada registro resultante da seleo, e para cada objeto carrega todos os atributos ou properties mapeadas com os valores lidos do banco de dados; 4. Framework adiciona todos os objetos instanciados no mapa de objetos persistidos; 5. Framework retorna uma lista com todos os objetos instanciados; 6. Aplicao manipula os objetos retornados na lista. No passo 2, caso a seleo do banco de dados no retorne nenhum registro: 1. Framework retorna uma lista vazia; 2. Retorna ao passo 6.

diferena que podem ser selecionados vrios objetos da mesma entidade de uma s vez. Pr-condies

Ps-condies Cenrio Fluxo alternativo 1

Exceo 1

Quadro 13 Caso de uso UC06 Obter lista de objetos de entidades

3.2.1.7

UC07 Remover objeto de entidade

O Quadro 14 mostra os detalhes do caso de uso UC07 - Remover objeto de


entidade.

Entenda-se como sendo a deleo de um objeto no banco de dados e remoo do

mesmo do gerenciador de objetos.

60

Pr-condies

Ps-condies Cenrio Principal

Exceo 1

Exceo 2

Exceo 3

UC07 Remover objetos de entidades Classes de entidades mapeadas; base de dados criada; gerenciador de objetos (TObjectManager) instanciado; conexo aberta no banco de dados; objeto j persistido e mapeado no gerenciador de objetos. Objeto removido do banco de dados; objeto removido do mapeamento no gerenciador de objetos. Passos 1. Aplicao invoca o mtodo Remove do TObjectManager, passando o objeto persistido como parmetro; 2. Framework valida o objeto que est sendo removido; 3. Framework deleta o registro do banco de dados. No passo 2, caso o objeto ainda no esteja mapeado: 1. Framework gera exceo informando que o objeto precisa estar mapeado para remover. No passo 2, caso o objeto no possua o atributo Id preenchido: 1. Framework gera exceo informando que no permitido remover um objeto sem o Id preenchido. No passo 3, caso o banco de dados dispare alguma exceo, como por exemplo, violao de chave estrangeira: 1. Framework repassa a exceo disparada pelo banco de dados para a aplicao.

Quadro 14 Caso de uso UC07 Remover objetos de entidades

3.2.2

Estrutura do framework

O framework foi dividido em duas partes principais: o motor de persistncia e o gerenciador de objetos. O motor de persistncia contm os componentes que juntos provm a infraestrutura bsica para a camada de persistncia, realizando gerao de cdigo SQL em tempo de execuo, tratando conexo com o SGBD e atuando na lgica de execuo dos comandos na base de dados. J o gerenciador de objetos disponibiliza uma interface de acesso ao framework de forma transparente para a aplicao, com mtodos de interao que manipulam objetos de entidades de forma puramente orientada a objetos. A aplicao interage com o gerenciador de objetos, cujo papel tambm controlar o ciclo de vida dos objetos de entidades e fazer cache de leitura em memria local. Conforme se pode ver na Figura 17, o motor de persistncia divido em trs componentes: os aplicadores de comandos, os geradores de SQL e o mediador de conexo. J o gerenciador de objetos contm apenas um componente, chamado obviamente de gerenciador de objetos. Ambos utilizam outro componente chamado explorador de metadados, que foi destacado parte e responsvel por coletar e manipular as informaes

61 de metadados atravs de RTTI.

Figura 17 Diagrama de componentes

3.2.2.1

Gerenciador de objetos

O componente Gerenciador de Objetos contm as classes responsveis por prover uma interface de persistncia transparente para a aplicao, com mtodos que delegam responsabilidades para o motor de persistncia. Alm disso, devem controlar o ciclo de vida dos objetos de entidades e fazer cache de leitura em memria local. O diagrama de classes da Figura 18 mostra as classes deste componente.

Figura 18 Diagrama de classes do gerenciador de objetos

As classes TObjectManager e TDatabaseManager so a interface para a aplicao, e

62 ambas possuem a conexo com o SGBD que utilizada para aplicao dos comandos. A
TDatabaseManager

possui mtodo para criao da estrutura da base de dados baseada nas

entidades registradas no framework e seus respectivos mapeamentos, criando todas as tabelas, chaves primrias, chaves nicas, chaves estrangeiras, sequncias e demais estruturas que possam ser mapeadas. J a classe TObjectManager disponibiliza mtodos para persistir, atualizar, remover e obter objetos de entidades do banco de dados, que so respectivamente os mtodos Persist, Merge, Remove e Find. O mtodo FindAll serve para obter uma lista com todas as instncias de uma determinada classe. Cada objeto que for persistido, atualizado ou obtido atravs da classe TObjectManager deve ser armazenado em seu mapa de identidade FObjects. Todos os objetos que so inseridos neste mapa devem obrigatoriamente ter o atributo identificador preenchido. Aps armazenado, o objeto passa a ser gerenciado pela classe TObjectManager, a qual deve detectar as alteraes feitas nos atributos do objeto. O segundo mapa denominado
FOldStateObjects

serve para armazenar cpias dos objetos gerenciados, com o estado

original do objeto no momento em que foi lido do SGBD, para que se possa comparar com o objeto gerenciado e determinar quais atributos foram alterados. O mtodo Flush serve para aplicar no SGBD as alteraes pendentes feitas nos objetos que esto gerenciados. O mtodo
Clear

serve para limpar os dois mapas do TObjectManager, fazendo com que todas as

instncias de entidades mantidas pelo gerenciador deixem de ser gerenciadas. A classe TObjectMap representa um mapa de objetos de entidades e deve implementar o padro de projeto IdentityMap. Para isto ela possui um TDictionary, classe nativa da linguagem Delphi com funcionalidade semelhante ao HashMap da linguagem Java. A chave do dicionrio uma combinao da classe da entidade com o seu identificador, encapsulados na classe TObjMapKey, e o valor do dicionrio o prprio objeto de entidade. Alm disto, a classe TObjectMap possui uma srie de funes utilitrias para que o seu contedo possa ser manipulado adequadamente pelo TObjectManager.

3.2.2.2

Aplicadores de comandos

Os Aplicadores de Comandos so as classes responsveis pela lgica de execuo de comandos no SGBD. Os comandos so inicialmente montados em uma estrutura orientada a objetos que define tabelas, construes, campos, filtragens, junes e projees que o

63 comando deve realizar. Esta estrutura passada como parmetro para o gerador de SQL que a traduz para cdigo SQL em strings utilizando o dialeto do banco especfico que varia de um gerador para outro. O cdigo SQL ento executado no banco, e pode ter ou no parmetros. Nos comandos de consulta como select, tambm responsabilidade do aplicador de comando interpretar o retorno da consulta e carregar o objeto, lista ou rvore de objetos a partir das informaes lidas do SGBD. Para cada comando que executado no banco, possvel interceptar a execuo do comando atravs de listeners que podem ser adicionados. Tais listeners podem ser utilizados para gerao de logs, por exemplo. O diagrama de classes da Figura 19 exibe as classes deste componente.

Figura 19 Diagrama de classes dos aplicadores de comandos

Para cada tipo de comando existe uma classe concreta responsvel, a fim de separar as diferentes lgicas. As classes TDeleter, TUpdater, TInserter e TSelecter so utilizadas pelo TObjectManager e aplicam comandos em Data Manipulation Language (DML7) enquanto as classes TTableCreator, TSequenceCreator e TForeignKeyCreator so utilizadas pelo TDatabaseManager e aplicam comandos em Data Definition Language

Segundo Leme (2008), DML a linguagem de manipulao de dados, que permite especificar operaes de recuperao e alteraes dos dados do banco de dados.

64 (DDL8). Todas as classes aplicadoras de comandos descendem de uma classe abstrata chamada
TAbstractCommandPerformer,

herdando os seguintes atributos:

a) a conexo com o SGBD, por onde ser aplicado o comando; b) uma instncia do gerador de SQL apropriada para o SGBD especfico ao qual o sistema est conectado, que ser utilizado para gerao do cdigo SQL; c) a referncia para a classe de entidade para a qual deve ser gerado o comando; d) a lista de listeners que sero disparados para cada comando executado. O listener de execuo de comandos no uma classe e sim uma interface que define apenas o mtodo ExecutingCommand. Desta forma os listeners podem ser implementados com mais flexibilidade.

3.2.2.3

Geradores de SQL

Este componente define os geradores de cdigo SQL, que so responsveis por interpretar as estruturas de comandos recebidas dos Aplicadores de Comandos e traduzi-las para cdigo SQL. O diagrama de classes da Figura 20 mostra as classes deste componente.

Conforme Leme (2008), DDL a linguagem de definio de dados que descreve a estrutura do banco de dados. Possui comandos de criao, alterao e excluso de tabelas e vises. Gera um catlogo a partir da descrio dos dados.

65

Figura 20 Diagrama de classes dos geradores de SQL

A interface ISQLGenerator define todos os mtodos disponveis para gerao de SQL, que cada gerador obrigado a implementar. Esta abstrao foi criada baseada no padro de projeto Strategy, a fim de tornar o framework facilmente extensvel adicionando suporte para diferentes SGBDs. Os Aplicadores de Comandos conhecem somente a ISQLGenerator, ignorando suas implementaes. Para cada SGBD suportado pelo framework, existe uma classe concreta que implementa ISQLGenerator. Como muitos bancos de dados possuem linguagens SQL similares, existem partes do cdigo de gerao de SQL que so repetitivas entre as classes dos geradores. Para resolver este problema foi criada uma classe intermediria chamada
TAnsiSQLGenerator

que rene esta lgica em comum. Desta forma, evitou-se duplicidade no

cdigo fonte do framework e delegou-se s classes correspondentes a cada SGBD apenas as especificidades de cada banco. O registro de todas as diferentes implementaes de geradores de SQL feita pela classe TSQLGeneratorRegister, que contm um dicionrio com as instncias dos geradores,

66 cada uma identificada por uma string que representa o nome do driver do gerador. Conforme declarado na interface ISQLGenerator, cada gerador deve implementar um mtodo
GetDriverName

que simplesmente deve retornar uma string que identifica para qual driver

este gerador foi implementado, como por exemplo Firebird. Quando os Aplicadores de Comandos so instanciados, eles requisitam atravs da funo GetGenerator da classe TSQLGeneratorRegister a instncia do gerador de SQL correspondente ao banco de dados atual, passando como parmetro o nome do driver obtido do objeto de conexo com o SGBD. Caso no haja nenhum gerador correspondente ao driver informado, gerada uma exceo. Para limitar em apenas uma instncia a classe TSQLGeneratorRegister e criar um nico ponto de acesso a ela, foi utilizado o padro de projeto Singleton. Todas as classes concretas de geradores de SQL se auto-registram atravs do mtodo RegisterGenerator da classe TSQLGeneratorRegister. As classes que so exibidas na parte inferior do diagrama, na seo Commands, representam os comandos que so instanciados e montados pelos Aplicadores de Comandos e passados como parmetro para os mtodos de gerao dos geradores de SQL. Seus atributos no so detalhados para que a especificao no fique extensa demais. Essas classes no devero ter regras de negcio e sim apenas armazenam dados para gerao dos comandos em uma estrutura organizada.

3.2.2.4

Mediador de conexo

Neste componente esto definidas as interfaces e classes que interagem com a API do driver do banco de dados, atuando como mediador entre o framework e os componentes de acesso direto ao SGBD. Foram definidas trs interfaces principais: a) IDBConnection: representa o objeto de conexo com o banco de dados, com mtodos para conectar, desconectar, verificar conexo aberta, criar statements e obter o nome do driver; b) IDBStatement: o objeto por onde so efetivamente executados os comandos no SGBD, com mtodos para atribuir o comando SQL, atribuir os parmetros para o comando, executar comandos imperativos e executar comandos de seleo. O mtodo de execuo de comandos de seleo retorna um objeto da interface

67
IDBResultSet;

c) IDBResultSet: representa o resultado tabular de um comando de seleo, com os registros lidos do banco de dados. Possui mtodos para ler os valores dos campos, navegar para o prximo registro e verificar se est vazio. Este componente utilizado apenas pelos Aplicadores de Comandos, os quais utilizam somente estas trs interfaces, sem conhecer suas implementaes. Desta forma, o framework mais facilmente extensvel, pois possvel substituir no somente o driver de conexo com o SGBD como tambm o conjunto de componentes internos que o acessam. Tais componentes poderiam ser, por exemplo, DBExpress ou Borland Database Engine (BDE). O diagrama de classes da Figura 21 apresenta as classes deste componente.

Figura 21 Diagrama de classes do mediador de conexo

As trs interfaces definidas neste componente podem ter sua lgica de interao com o SGBD implementadas por completo em classes novas, ou ento reutilizarem esta lgica de outras classes que j realizam este servio. Para isto podem ser reaproveitadas bibliotecas de terceiros ou componentes nativos do Delphi aplicando o padro de projeto Adapter. Para o funcionamento do framework, foram utilizados os componentes da biblioteca DBExpress, que so componente nativos no Delphi 2010. Foi utilizado o padro Adapter utilizando herana, dando origem s classes de adaptao TDBExpressConnectionAdapter,
TDBExpressStatementAdapter

e TDBExpressResultSetAdapter. Tais classes descendem

das classes do DBExpress, que so TSQLConnection e TSQLQuery, e implementam as interfaces definidas pelo framework. A classe TSQLQuery foi estendida tanto para atender

68
IDBStatement

quanto para IDBResultSet pelo fato de ela por si s implementar as

funcionalidades definidas por estas duas interfaces. A classe TDBParam serve apenas para encapsular um parmetro que passado para um statement definindo seu nome, tipo e valor. A classe TEnumerable<T> nativa do Delphi e representa uma coleo genrica enumervel com elementos do tipo T.

3.2.2.5

Explorador de metadados

Este componente define as classes que so responsveis por explorar os metadados de mapeamento objeto-relacional declarados nas classes de entidades da aplicao, fornecendo informaes detalhadas de mapeamento para os demais componentes do framework, alm de interagir com os objetos de entidades. As trs classes definidas neste componente so utilitrias e implementam o padro de projeto Singleton para criar um ponto de acesso a elas, e para que possa haver apenas um objeto de cada instanciado no sistema. Estas classes fazem cache das informaes de mapeamento para garantir um bom desempenho. O atributo FInstance e o mtodo
GetInstance

fazem parte da implementao do padro Singleton. O diagrama de classes da

Figura 22 mostra as classes deste componente.

Figura 22 Diagrama de classes do explorador de metadados

69 A classe TRttiExplorer serve para centralizar a interao com a API do RTTI do Delphi, obtendo as informaes de mapeamento objeto-relacional das classes de entidades e interagindo com os objetos de entidades atravs de RTTI. Possui mtodos para: a) obter a tabela qual a classe de entidade est mapeada; b) obter as chaves nicas da classe de entidade; c) obter as associaes da classe de entidade com outras classes de entidades; d) obter as colunas s quais a classe de entidade est mapeada, cada coluna mapeada a um atributo ou property da classe; e) obter a sequence para gerao de valor para o campo id da classe de entidade; f) obter o atributo ou property auto-gerada de uma classe de entidade; g) obter o valor do atributo ou property de um objeto de entidade; h) atribuir um determinado valor a um atributo ou property de um objeto de entidade; i) comparar dois objetos da mesma classe para determinar quais atributos ou properties esto com valores diferentes; j) copiar valores dos atributos ou properties de um objeto para outro, sendo que os dois objetos so da mesma classe. A classe TMappedClasses responsvel por realizar o registro de todas as classes de entidades mapeadas no framework, para que se possa ter uma lista de todas as classes mapeadas. O framework possui por padro a habilidade de registrar automaticamente todas as classes de entidades mapeadas que esto sendo utilizadas pela aplicao. Em situaes especiais, esta configurao pode ser desabilitada e as classes podem ser registradas manualmente atravs da TMappedClasses. A TMappedClasses possui mtodos para: a) registrar uma classe de entidade no framework; b) obter a lista de classes registradas no framework. A classe TClassHierarchyExplorer serve para fornecer informaes de herana entre classes de entidades. No Delphi, a partir de uma classe, possvel descobrir qual sua classe pai atravs do atributo nativo ClassParent, porm no existe uma alternativa fcil para obter suas classes filhas. O objetivo maior da classe TClassHierarchyExplorer fornecer esta navegabilidade de cima para baixo dentro da hierarquia de classes, mas apenas para as classes de entidades mapeadas. Portanto, ela utiliza a TMappedClasses para obter a lista com todas as classes mapeadas e ento cruza as informaes de parentesco entre estas classes para montar uma representao das rvores de herana. A classe

TClassHierarchyExplorer

possui mtodos para:

a) obter, a partir de uma classe, a lista de todas as classes descendentes, sejam filhas,

70 netas, ou qualquer nvel inferior; b) obter, a partir de uma classe, a lista de todas as suas subclasses diretas, ou seja, apenas as que esto no primeiro nvel abaixo da classe que foi passada como parmetro.

3.2.3

Interao entre as classes

O diagrama de seqncia da Figura 23 mostra a interao entre as principais classes do framework para efetuar a persistncia de um objeto de entidade. So mostradas em nvel macro as principais trocas de mensagens que so feitas desde a chamada do mtodo persist no TObjectManager, que a interface do framework com a aplicao, at a execuo do comando de insero no banco de dados. Alguns detalhes de implementao foram omitidos, bem como regras de negcio. Foi emitida, por exemplo, a exceo a ser gerada quando o objeto a ser persistido j se encontra persistido. A execuo do comando de insero no banco de dados feita no mtodo Execute da interface IDBStatement, e sua implementao pode variar. A implementao padro desta interface a classe TDBExpressStatementAdapter, onde o mtodo Execute dispara o mtodo ExecSQL da classe TSQLQuery.

71

Figura 23 Diagrama de seqncia do framework para o mtodo Persist

3.3

MODELO DE ANOTAO PARA MAPEAMENTO

Para que possa ser realizado o mapeamento objeto-relacional entre as entidades da aplicao e o banco de dados, foi criado um modelo de anotao baseado em Atributos Customizados, recurso do Delphi que foi descrito na fundamentao terica, tpico 2.4. Basicamente, a elaborao deste modelo foi a criao de um conjunto de classes descendentes da classe nativa TCustomAttribute. Muitos dos atributos criados foram inspirados nas anotaes da especificao JPA, implementada pelo framework Hibernate. So mostradas na Figura 24 todas as classes que foram criadas. A seguir, detalha-se o significado de cada classe para o mapeamento. Por fim, mostrado um exemplo de como

72 pode ser utilizado este modelo de anotao para mapear uma classe de entidade na aplicao.

Figura 24 Classes do modelo de anotao

Segue abaixo a lista de classes que foram criadas, com seu respectivo significado: a) Entity: Define uma classe como classe de entidade. Uma classe de entidade uma classe que pode ser persistida. Este atributo deve ser anotado acima da declarao da classe e seu construtor no possui nenhum parmetro; b) Id: Define o campo que representa o identificador desta classe. Tal campo deve ter um valor nico, sem significado para o mundo real, e deve ser de algum tipo numrico inteiro como LongInt ou Integer. Com isto mapeia-se este campo para a chave primria da tabela no banco de dados. A anotao do atributo Id pode ser feita acima de um atributo ou property da classe, tambm sem parmetros. Toda classe deve possuir um e somente um Id. Se o Id for anotado na classe pai no se deve anotar o Id na classe filha; c) Table: Define em qual tabela do banco de dados a classe atual ser persistida. Este atributo deve ser anotado acima da declarao da classe e possui dois parmetros: o nome da tabela e o esquema desta tabela no banco de dados; d) Autogenerated: Define um campo da classe como gerado automaticamente. Com isto, o framework no gerar um valor para este atributo e ir delegar ao banco de dados a gerao do seu valor atravs do recurso de auto-incremento de uma coluna. Pode ser anotado acima de um atributo ou property. Em SGBDs que no

73 suportam colunas auto-incrementadas, esta anotao ignorada; e) UniqueConstraint: Define uma chave nica composta para a tabela no banco de dados. No necessrio declarar uma chave nica para o campo que foi definido como Id, porque esta chave j automaticamente mapeada como chave primria. Alm disto, chaves nicas compostas por apenas um campo podem ser mapeadas mais facilmente na anotao do atributo Column, descrita abaixo. O atributo
UniqueConstraint

pode ser anotado uma ou mais vezes acima de cada classe, e

seus parmetros so uma lista de strings com os nomes dos campos da chave nica; f) Sequence: Define uma sequence para gerao de valores para um campo da classe. Recebe trs parmetros: o nome da sequence, o valor inicial e o valor de incremento. Pode ser anotado acima de um atributo ou property. Esta anotao utilizada apenas ao utilizar SGBDs que suportam sequences, caso contrrio ela ignorada pelo framework e no influencia no mapeamento; g) Association: Define uma associao da classe atual para outra classe de entidade, que pode ser inclusive a prpria classe. Para todo atributo de uma classe de entidade cujo tipo tambm uma classe de entidade, deve-se anotar uma
Association

mapeando esta associao para que o framework saiba como trat-la.

O parmetro FetchType o tipo de carregamento, que pode ser ftLazy ou


ftEager. ftLazy

significa que o atributo ser carregado somente na primeira vez

que for requisitado, implementando o padro de projeto Lazy Load. ftEager significa que ser carregando j no momento em que o objeto atual for carregado. O parmetro Required indica se o atributo requerido para a classe e ir influenciar no modo como o sistema faz junes nos comandos select. Se o campo requerido, ser feito inner join, caso contrrio ser feito left join. E o ltimo parmetro Cascade define um conjunto de aes a serem feitas em cascata para esta associao. Estas aes podem ser Persist, Merge, Remove, Refresh. Uma ao de cascata do tipo Persist indica, por exemplo, que quando o objeto atual for gravado no banco de dados, antes disto ser gravado o objeto que est atribudo nesta associao. O atributo Association pode ser anotado acima de um atributo ou property; h) ManyValuedAssociation: Define uma associao para outra classe em um atributo multivalorado, como por exemplo, uma lista de itens em uma classe de

74 nota fiscal. Possui todas as propriedades de uma Association e mais uma propriedade opcional chamada MappedBy, na qual deve ser informado o nome do atributo ou property da classe associada que faz a associao inversa correspondente, nos casos onde existe associao bidirecional. Em associaes unidirecionais, o parmetro MappedBy no deve ser informado. Para que o framework consiga determinar a classe que est sendo mapeada em uma
ManyValuedAssociation,

o atributo ou property anotado deve utilizar uma lista

genrica como TList<T>; i)


JoinColumn:

utilizada junto com as anotaes de Association e define uma

das colunas que compe a chave estrangeira para a tabela da classe associada. Para cada anotao de Association, deve ser anotada uma ou mais JoinColumns, dependendo da quantidade de colunas que compe a chave estrangeira. As anotaes de Association e JoinColumn so parte da implementao do padro de projeto Foreign Key Mapping e devem ser anotadas juntas, uma abaixo da outra; j)
ForeignJoinColumn:

utilizada

junto

com

as

anotaes

de

ManyValuedAssociation

e define uma das colunas que compe a chave

estrangeira da tabela associada para a tabela atual, caso a associao seja unidirecional. Em associaes bidirecionais este atributo no necessrio, pois o mapeamento feito com o MappedBy. As anotaes de ManyValuedAssociation e
ForeignJoinColumn

tambm so parte da implementao do padro de projeto

Foreign Key Mapping; k) Column: Define o mapeamento entre uma coluna da tabela no banco de dados e um atributo ou property da classe de entidade. Seus parmetros so: nome da coluna, propriedades da coluna, comprimento, preciso e escala. O comprimento precisa ser informado somente em colunas do tipo string. A preciso e a escala, somente em colunas numricas de tipos reais como Double ou Currency. As propriedades da coluna so um conjunto de propriedades que podem ser Unique, Required,
DontInsert

e DontUpdate. Unique define a coluna como sendo nica, mapeando

uma chave nica no banco de dados. Required define que a coluna not null no banco de dados. DontInsert e DontUpdate definem, respectivamente, que esta coluna no ser includa em comandos de insert e de update a serem efetuados no SGBD para esta entidade. O atributo Column pode ser anotado acima de um

75 atributo ou property; l)
Inheritance:

Define mapeamento de herana, indicando uma classe como sendo

raiz de uma hierarquia de classes de entidades. Deve ser mapeada acima da classe que raiz da hierarquia, informando o parmetro Strategy que define a estratgia de herana, que pode ser
TablePerConcreteClass, SingleTable

ou

JoinedTables. TablePerConcreteClass

indica que cada classe concreta da

hierarquia dever ser mapeada para uma diferente tabela no banco de dados, a qual contm todas as colunas da classe incluindo as colunas herdadas. SingleTable indica que todas as classes da hierarquia sero mapeadas para apenas uma tabela no banco, que contm todas as colunas possveis de todas as classes. Para esta estratgia, necessrio utilizar os atributos
DiscriminatorColumn

DiscriminatorValue

para realizar o mapeamento corretamente. A terceira

estratgia JoinedTables ndica que ser criada uma tabela para cada classe da hierarquia, mesmo para as classes abstratas, sendo que cada tabela contm somente os campos declarados em cada classe correspondente, alm da chave primria e uma chave estrangeira para a tabela que representa a classe pai; m) DiscriminatorColumn: Aplica-se a herana do tipo SingleTable e define uma coluna que ser utilizada para discriminar os registros da tabela, indicando a qual classe cada registro pertence. Os parmetros so nome da coluna, tipo do discriminador e comprimento. O tipo do discriminador pode ser String ou
Integer

e o comprimento opcional e aplica-se somente se o tipo do for


String.

discriminador

atributo

DiscriminatorColumn

deve

obrigatoriamente ser anotado acima da classe raiz da hierarquia; n) DiscriminatorValue: Aplica-se a herana do tipo SingleTable e define o valor discriminativo da classe atual, para que o framework saiba determinar de qual classe cada objeto lido da tabela nica. Para cada classe concreta da hierarquia, deve ser anotado acima da declarao da classe informando o parmetro que o valor discriminativo, que pode ser String ou Integer. Cada classe concreta dever ter um valor discriminativo diferente. O Quadro 15 mostra um exemplo de como realizar as anotaes em uma classe de entidade.

76
type [Entity] [Table('NOTAS_FISCAIS')] [Sequence('SEQ_NOTAS_FISCAIS')] [UniqueConstraint(NUMERO, ID_CLIENTE)] TNotaFiscal = class private FId: LongInt; FNumero: Integer; FEmissao: TDateTime; FCliente: TCliente; FItens: TList<TItemNota>; public [Id] [AutoGenerated] [Column('ID', [cpUnique, cpRequired])] property Id: LongInt read FId write FId; [Column('NUMERO', [cpRequired])] property Numero: Integer read FNumero write FNumero; [Column('DATA_EMISSAO', [cpRequired])] property Emissao: TDateTime read FEmissao write FEmissao; [Association(ftEager, orRequired, ctCascadeAll)] [JoinColumn('ID_CLIENTE')] property Cliente: TCliente read FCliente write FCliente; [ManyValuedAssociation(ftEager, orRequired, ctCascadeAll)] [ForeignJoinColumn(ID_NOTA_FISCAL, [cpRequired])] property Itens: TList<TItemNota> read FItens write FItens; end;

Quadro 15 Exemplo de anotaes em classe de entidade

Neste exemplo, foram utilizadas as seguintes classes de atributos customizados:


Enitity, Table, Sequence, UniqueConstraint, Id, AutoGenerated, Column, Association, JoinColumn, ManyValuedAssociation

e ForeignJoinColumn. Os atributos de colunas e

associaes foram anotados nas properties Id, Numero, Emissao, Cliente e Itens. O framework tambm permite anot-los diretamente nos atributos da classe FId, FNumero,
FEmissao, FCliente

e FItens. Esta flexibilidade foi criada para o caso de o programador

no querer declarar properties em suas classes para encapsular os atributos. J os atributos


Entity, Table, Sequence

e UniqueConstraint devem obrigatoriamente ser anotados na

classe. No caso de herana entre classes, a classe filha pode herdar as anotaes de Table e
Sequence

da classe pai. As classes de atributos Inheritance, DiscriminatorColumn e so utilizadas apenas em casos de herana, por isto no aparecem no

DiscriminatorValue

exemplo. Para declarar estas anotaes em sua classe, o programador deve adicionar a unidade
MetadataEngine.Attributes

na clusula uses da unidade onde est sendo declarada a

77 classe. Sem isto o editor do Delphi no reconhecer as classes de atributos customizados que esto sendo utilizados, e funcionalidades como code completion no funcionaro.

3.4

IMPLEMENTAO

A seguir so mostradas as tcnicas e ferramentas utilizadas na implementao do framework, as convenes seguidas, bem como detalhes da implementao dos componentes do framework. Por fim, mostrada sua operacionalidade.

3.4.1

Tcnicas e ferramentas utilizadas

A implementao do framework seguiu os conceitos da orientao a objetos, e foi separada em diferentes unidades e classes de acordo com as diferentes complexidades de implementao. Conforme previsto na especificao, a implementao fez uso dos padres de projeto: a) DAO, visto que o gerenciador de objetos um objeto DAO; b) Singleton, usado nas classes TMappedClasses, TClassHierarchyExplorer,
TSQLGeneratorRegister, TGlobalConfigs

e TRttiExplorer;

c) Adapter, usado para implementao do adaptador de conexo com o DBExpress; d) Strategy, usado nos geradores de SQL para implementar suporte a vrios SGBDs; e) Identity Field, implementado atravs do atributo customizado Id e rotinas que o tratam, identificando unicamente os objetos; f) Identity Map, implementado na classe TObjectMap que utilizada pelo gerenciador de objetos; g) Foreign Key Mapping, implementado com os atributos customizados

Association, ManyValuedAssociation

e suas rotinas de tratamento;

h) Lazy Load, implementado como estratgia de carregamento nos atributos


Association

e ManyValuedAssociation, utilizando a estrutura Proxy<T> e

rotinas especficas de tratamento. O framework foi implementado utilizando o ambiente de desenvolvimento

78 Embarcadero Delphi 2010 para Windows. Foram utilizados os componentes da Visual Component Library (VCL9) e RunTime Library (RTL10) do Delphi, alm dos componentes DBExpress de acesso ao banco de dados, tambm nativos. No foi utilizada nenhuma biblioteca que no fosse nativa, portanto todo o seu cdigo fonte depende apenas do Delphi para compilar e executar. Alguns recursos que foram utilizados, como Atributos Customizados e a nova API do RTTI, esto disponveis apenas a partir do Delphi 2010, portanto seu cdigo fonte no pode ser facilmente portado para verses anteriores. Durante a implementao do framework, foi utilizado o sistema de controle de verso Subversion para organizar as verses do cdigo fonte. Como aplicativo cliente foi utilizado o TortoiseSVN. Segundo TIGRIS (2010), TortoiseSVN uma ferramenta cliente de Subversion integrada ao Windows Explorer. Ela possui cdigo fonte aberto e realiza controle de revises, verses e fontes. Como no se trata de um plugin de integrao com alguma IDE especfica, pode ser utilizada idenpendentemente da ferramenta de desenvolvimento ou linguagem de programao. Foram utilizados os SGBDs Firebird na verso 2.1 e MySQL na verso 5.1. Tanto o componente servidor quanto o componente cliente dos dois SGBDs foram instalados em uma mquina local. Para confirmar as informaes gravadas pelo framework no banco de dados Firebird, foi utilizada a ferramenta de administrao de banco de dados Flamerobin. No caso do MySQL, foi utilizada a ferramenta MySQL Query Browser.

3.4.2

Convenes seguidas

A implementao seguiu algumas convenes para tornar o cdigo fonte organizado, legvel e reutilizvel. Seguem algumas convenes utilizadas: a) o cdigo fonte foi implementado utilizando unidades, classes, identificadores e mensagens em idioma ingls, para abrir a possibilidade de tornar o cdigo fonte pblico e poder ser editado por outras pessoas, inclusive de outros pases; b) para cada tipo de exceo que o framework gera foi criada uma classe de exceo

Conforme Embarcadero (2009), VCL um conjunto de componentes criado pela Borland para desenvolvimento na linguagem Delphi. Ela inclui componentes visuais, no-visuais e classes utilitrias para construo de aplicaes para Windows, web, bancos de dados e console.
10

Segundo Embarcadero (2009), por trs da VCL o Delphi fornece uma vasta biblioteca de rotinas e classes, chamada de RTL, que prov funcionalidades comuns necessrias em qualquer tipo de aplicao.

79 distinta. Todas essas classes descendem da classe EOPFBaseException definida no framework, que por sua vez descende da classe nativa Exception. As classes de excees foram reunidas em diferentes units de acordo com seu contexto; c) todas as alocaes e deslocaes dinmicas de objetos foram implementadas de forma a evitar vazamentos de memria. Foi utilizado o gerenciador de memria11 nativo do Delphi para detectar vazamentos de memria no framework, e foram resolvidos todos os vazamentos encontrados durante os testes; d) sempre que possvel, foram utilizadas estruturas de dados nativas da linguagem, a fim de tornar o cdigo fonte do framework mais facilmente portvel para as prximas verses do Delphi, sem precisar realizar migraes de estruturas especficas; e) sempre que possvel, foram utilizadas colees genricas como TList<T>,
TObjectList<T>

e TDictionary<TKey,

TValue>,

declaradas na unidade

Generics.Collections,

ao invs das colees antigas da unidade Classes. Estas

estruturas genricas esto disponveis no Delphi a partir da verso 2009.

3.4.3

Implementao dos componentes do framework

Os componentes do framework foram implementados conforme apresentado na especificao. Nessa seo so mostrados alguns trechos do cdigo fonte das principais classes de cada componente. No componente Gerenciador de Objetos, a principal classe a TObjectManager. O Quadro 16 mostra a implementao do mtodo Persist da classe TObjectManager.

11

Conforme Embarcadero (2006), a partir do Delphi 2006 existe um gerenciador de memria nativo que permite reportar todos os blocos de memria que no foram liberados. Esta funcionalidade pode ser habilitada configurando a varivel ReportMemoryLeaksOnShutdown para True. Com isto, um relatrio de vazamentos de memria aparece em uma mensagem na tela ao fechar a aplicao.

80
procedure TObjectManager.Persist(Entity: TObject); var Inserter: TInserter; begin if FObjects.IsMapped(Entity) then raise EObjectAlreadyPersistent.Create(Entity); if FObjects.HasIdValue(Entity) then raise ECannotPersististWithId.Create(Entity); CascadePersist(Entity); Inserter := FCommandFactory.GetCommand<TInserter>(Entity.ClassType); try if TRttiExplorer.GetInstance.HasSequence(Entity.ClassType, True) then Inserter.LoadIdFromSequence(Entity); Inserter.Insert(Entity); FObjects.Add(Entity); FOldStateObjects.Add(TRttiExplorer.GetInstance.Clone(Entity)); finally Inserter.Free; end; end;

Quadro 16 Implementao do mtodo Persist

No componente Explorador de Metadados, a principal classe a TRttiExplorer. O Quadro 17 mostra a implementao do mtodo GetChangedMembers da classe
TRttiExplorer.

Este mtodo serve para detectar quais atributos ou properties foram

alterados em um objeto. O gerenciador de objetos chama este mtodo passando como parmetro duas verses do mesmo objeto: a verso atual e a cpia que foi criada refletindo o estado em que se encontrava no banco de dados.

81
function TRttiExplorer.GetChangedMembers(OriginalObj, DirtyObj: TObject): TList<string>; var RttiType: TRttiType; Member: TRttiMember; OriginalValue, DirtyValue: TValue; C: TColumn; begin Assert(OriginalObj.ClassType = DirtyObj.ClassType); RttiType := FContext.GetType(OriginalObj.ClassType); Result := TList<string>.Create; for C in GetColumns(OriginalObj.ClassType, True) do begin if not C.IsDiscriminator then begin case C.MemberType of mtField: Member := RttiType.GetField(C.ClassMemberName); mtProperty: Member := RttiType.GetProperty(C.ClassMemberName); else Member := nil; end; OriginalValue := GetMemberValue(OriginalObj, Member.Name); DirtyValue := GetMemberValue(DirtyObj, Member.Name); if not ValueIsEqual(OriginalValue, DirtyValue) then Result.Add(Member.Name); end; end; end;

Quadro 17 Implementao do mtodo GetChangerMembers

No componente Aplicadores de Comandos, no existe uma classe principal e sim vrias classes aplicadoras de comandos, todas descendentes de

TAbstractCommandPerformer. TDeleter.

O Quadro 18 mostra o cdigo do mtodo Delete da classe

82
procedure TDeleter.Delete(Entity: TObject); var Command: TDeleteCommand; SQLField: TSQLWhereField; IdColValue: TValue; IdValue: Variant; ParamName, SQL: string; Params: TObjectList<TDBParam>; begin Command := TDeleteCommand.Create; try SQLField := TSQLWhereField.Create(CreateSQLTable,FIdCol.Name,woEqual); Command.Table := CreateSQLTable; Command.WhereFields.Add(SQLField); SQL := FGenerator.GenerateDelete(Command); IdColValue := TRttiExplorer.GetInstance.GetColumnValue(Entity,FIdCol); IdValue := TUtils.ValueToVariant(IdColValue); ParamName := FGenerator.GetDefaultWhereParamName(SQLField); Params := TObjectList<TDBParam>.Create; try Params.Add(TDBParam.Create(ParamName,FIdCol.FieldType,IdValue)); Execute(SQL,Params,False); finally Params.Free; end; finally Command.Free; end; end;

Quadro 18 Implementao do mtodo Delete

No componente Geradores de SQL, foram criadas classes geradoras de comandos SQL e classes auxiliares. A maior classe deste componente a TAnsiSQLGenerator. O Quadro 19 mostra a implementao do mtodo GenerateInsert da classe TAnsiSQLGenerator.

83
function TAnsiSQLGenerator.GenerateInsert(Cmd: TInsertCommand): string; var FieldNames: TList<string>; I: Integer; begin Assert(Cmd.InsertFields.Count > 0); FieldNames := GetFieldNames(Cmd.InsertFields, False); try Result := 'INSERT INTO '; if Cmd.Table.Schema <> '' then Result := Result + Cmd.Table.Schema + '.'; Result := Result + Cmd.Table.Name + ' ('#13#10' ' + TUtils.ConcatStrings(FieldNames) + ')'#13#10'VALUES ('#13#10' ';

for I := 0 to Cmd.InsertFields.Count - 1 do begin if I > 0 then Result := Result + ', '; Result := Result + ':' + GetDefaultParamName(Cmd.InsertFields[I]); end; Result := Result + ');'; finally FieldNames.Free; end; end;

Quadro 19 Implementao do mtodo GenerateInsert

Ainda no componente Geradores de SQL foram criadas classes de comandos, que servem para encapsular as informaes necessrias para gerao de um comando SQL. Alguns exemplos destas classes so TSelectCommand, TInsertCommand, TUpdateCommand,
TDeleteCommand

e TCreateTableCommand, entre outras. Todas as classes que encapsulam

comandos de DML descendem de uma classe abstrata chamada TDMLCommand. O Quadro 20 mostra um trecho de cdigo fonte de algumas destas classes para exemplificar.

84
type TDMLCommand = class abstract private FTable: TSQLTable; public property Table: TSQLTable read FTable write FTable; end; TSelectCommand = class(TDMLCommand) private FSelectFields: TObjectList<TSQLSelectField>; FJoins: TObjectList<TSQLJoin>; FWhereFields: TObjectList<TSQLWhereField>; FGroupByFields: TObjectList<TSQLField>; FOrderByFields: TObjectList<TSQLOrderField>; public // Getters e setters dos atributos privados ocultados... end; TInsertCommand = class(TDMLCommand) private FInsertFields: TObjectList<TSQLField>; public // Getters e setters dos atributos privados ocultados... end;

Quadro 20 Classes de comandos nos geradores de SQL

Para que se possa entender melhor, so mostrados no Quadro 21 trechos de cdigo das classes auxiliares que compe as classes de comandos.

85
type TSQLTable = class private FName: string; FSchema: string; FAlias: string; public // Getters e setters dos atributos privados ocultados... end; TSQLField = class private FTable: TSQLTable; FField: string; public // Getters e setters dos atributos privados ocultados... end; TJoinType = (jtInner, jtLeft); TSQLJoinSegment = class private FPKField: TSQLField; FFKField: TSQLField; public // Getters e setters dos atributos privados ocultados... end; TSQLJoin = class private FJoinType: TJoinType; FSegments: TObjectList<TSQLJoinSegment>; public // Getters e setters dos atributos privados ocultados... end; // Demais classes auxiliares...

Quadro 21 Classes auxiliares nos geradores de SQL

3.4.4

Funcionalidades e estratgias implementadas

A seguir so apresentadas algumas funcionalidades e estratgias que foram implementadas no framework.

3.4.4.1

Mapeamento de herana

Foi implementado suporte a mapeamento de herana. Para tal, foram implementadas todas as trs estratgias de herana explicadas na fundamentao terica:

86 a) herana de tabela por classe concreta; b) herana de tabela nica; c) herana de tabela por subclasse. Tais estratgias podem ser configuradas ao realizar a anotao do atributo customizado
Inheritance

nas classes de entidades, passando como parmetro a enumerao que estratgia desejada:
isTablePerConcreteClass, isSingleTable

representa

ou

isJoinedTables.

3.4.4.2

Mapeamento de associaes

Para mapeamento de associaes entre entidades, foram implementados os seguintes mapeamentos: a) muitos-para-um; b) um-para-muitos. Estes mapeamentos representam, respectivamente, associaes diretas e agregaes. Associaes do tipo um-para-um no foram implementadas, mas possvel utilizar uma associao muitos-para-um e limitar a cardinalidade na prpria aplicao. Associaes do tipo muitos-para-muitos tambm no foram implementadas, mas podem ser decompostas em associaes um-para-muitos dos dois lados da associao, simulando uma associao muitospara-muitos. Associaes do tipo muitos-para-muitos com tabela associativa podem ser simuladas da mesma forma, mas neste caso necessrio criar explicitamente a classe associativa. O framework no est preparado para cri-la automaticamente. Para utilizar associaes do tipo muitos-para-um, utiliza-se o atributo customizado
Association

anotado acima do atributo ou property da classe que referencia a outra classe de

entidade. Para utilizar associaes do tipo um-para-muitos, utiliza-se o atributo customizado


ManyValuedAssociation,

anotado acima do atributo ou property da classe que armazena a

lista de objetos. O mapeamento de associaes no framework reflete a utilizao do padro de projeto Foreign Key Mapping. O framework mapeia as anotaes de Association e
ManyValuedAssociation

para chaves estrangeiras no banco de dados.

87 3.4.4.3 Object Identifier

Para garantir a unicidade dos objetos, foram implementados tratamentos para a regra do Object Identifier utilizando os conceitos do padro de projeto Identity Field. Como o framework no deve alterar nem adicionar atributos s classes de entidades da aplicao, resolve-se da seguinte maneira: o programador deve declarar em suas classes um atributo que armazenar o identificador do objeto, e anotar acima deste o atributo customizado Id. A partir deste momento, o framework associa este atributo chave primria da tabela. Para o funcionamento correto da persistncia desta entidade, o atributo Id no deve ter significado e deve ser de algum tipo numrico inteiro, como Integer ou LongInt. O valor deste campo gerado automaticamente pelo framework no momento apropriado para a persistncia, mas para isto deve-se utilizar a anotao Sequence ou AutogeneratedValue. O framework atualmente no suporta um Id composto por mais de um campo.

3.4.4.4

Nullable

Para que a aplicao possa manipular o valor null em atributos de entidades que so de tipos primitivos, foi implementado um tipo especial chamado Nullable, semelhante estrutura Nullable da plataforma .NET, citada na fundamentao terica. O Nullable um tipo genrico e declarado como Nullable<T>. Por ser genrico, pode-se decompor em vrios outros tipos como Nullable<string>, Nullable<boolean>, Nullable<TDateTime>, entre outros. No h restries para o tipo T, podendo aceitar qualquer tipo, inclusive classes como
TCliente

por exemplo. Porm, para classes no h a necessidade de usar a estrutura Nullable,

j que a elas pode ser atribudo o valor nil. O tipo Nullable<T> foi implementado como um record no Delphi. O Quadro 22 mostra o record com seus atributos e mtodos.

88
type Nullable<T> = record private FValue: T; FHasValue: Boolean; // Default False class procedure CheckNullOperation(Left, Right: Nullable<T>); static; function GetIsNull: Boolean; function GetValue: T; procedure SetValue(const Value: T); function GetValueOrDefault: T; public constructor Create(Value: T); overload; property property property property HasValue: Boolean read FHasValue; IsNull: Boolean read GetIsNull; Value: T read GetValue write SetValue; ValueOrDefault: T read GetValueOrDefault;

class operator Implicit(Value: TNullRecord): Nullable<T>; class operator Implicit(Value: T): Nullable<T>; class operator Implicit(Value: Nullable<T>): T; class operator Explicit(Value: T): Nullable<T>; class operator Explicit(Value: Nullable<T>): T; class operator Equal(Left, Right: Nullable<T>): Boolean; class operator NotEqual(Left, Right: Nullable<T>): Boolean; class operator GreaterThan(Left, Right: Nullable<T>): Boolean; class operator GreaterThanOrEqual(Left, Right: Nullable<T>): Boolean; class operator LessThan(Left, Right: Nullable<T>): Boolean; class operator LessThanOrEqual(Left, Right: Nullable<T>): Boolean; end;

Quadro 22 Implementao da estrutura Nullable

Basicamente o Nullable<T> contm um atributo para o valor, FValue, do tipo T, e um atributo para indicar a presena ou no de valor, FHasValue, do tipo Boolean. Se FHasValue for False, o valor armazenado por FValue indefinido. Neste estado, a estrutura
Nullable<T>

no permite que o valor seja acessado, pois no h valor. Qualquer tentativa de

leitura ou utilizao do valor indefinido gerar uma exceo. Os atributos internos do Nullable<T> foram colocados como privados. Foram utilizados mtodos dinmicos e estticos para realizar o controle de acesso. Tambm foram implementados operadores para converso implcita e explcita para o tipo T, para o valor
null,

e operadores de comparao. No Delphi, estes operadores definem qual comportamento

ser executado ao comparar duas variveis do tipo Nullable<T> ou ento comparar uma varivel do tipo Nullable<T> com uma do tipo T, por exemplo. Grande parte destas funcionalidades utilizadas, como tipos genricos, records com mtodos, operadores, e

89 definio de visibilidades em records no existiam em verses anteriores ao Delphi 2009. A razo do Nullable<T> ter sido criado como record ao invs de classe a instanciao implcita. No Delphi, toda classe precisa ser explicitamente instanciada antes de ser utilizada, e destruda logo aps. J nos records isso no necessrio, pois eles so implicitamente instanciados. Como no faria muito sentido o programador ter que instanciar e destruir cada atributo anulvel de uma classe, esta alternativa foi muito mais confortvel e transparente.

3.4.4.5

Lazy Load

O framework utiliza o Lazy Load no carregamento de entidades associadas. No utilizado Lazy Load em atributos que no so associaes, ou seja, todos os demais atributos de uma entidade so carregados ao mesmo tempo quando o framework carrega a entidade. Alm disso, para utilizao do Lazy Load, deve-se definir a estratgia de carregamento
ftLazy

ao anotar a associao, caso contrrio a entidade associada ser tambm carregada no

mesmo momento. Para a implementao do padro de projeto Lazy Load foi criada uma estrutura genrica especial declarada como Proxy<T>. As alternativas de implementao do Lazy Load so citadas na fundamentao terica, das quais foram escolhidas o proxy virtual e o armazenador de valor. A soluo elaborada uma juno destas duas alternativas. A Quadro 23 mostra o cdigo fonte da estrutura Proxy<T>.
type Proxy<T: class> = record private FValue: T; FLoaded: Boolean; FId: LongInt; FManager: TObjectManager; function GetValue: T; procedure SetValue(const Value: T); public property Value: T read GetValue write SetValue; class operator Equal(Left, Right: Proxy<T>): Boolean; class operator NotEqual(Left, Right: Proxy<T>): Boolean; end;

Quadro 23 Implementao da estrutura Proxy

O Proxy<T> um record genrico que encapsula um valor do tipo T, onde T obrigatoriamente deve ser uma classe. Na prtica, T deve ser uma classe de entidade mapeada, como TCliente por exemplo. Cada Proxy<T> contm um atributo onde armazenado o valor

90 depois de carregado, um indicador de valor j carregado, o Id do objeto a ser carregado e uma referncia ao gerenciador de objetos. O valor da entidade acessado atravs da property Value. No momento em que esta property lida, o proxy verifica se o valor j foi carregado. Caso ainda no tenha sido carregado, ele carrega o objeto de entidade utilizando o gerenciador de objetos, passando como parmetro o Id do objeto. A classe do objeto a ser requisitado a classe genrica T. A implementao dos mtodos GetValue e SetValue mostrada na Quadro 24.
function Proxy<T>.GetValue: T; begin if not FLoaded then begin if FId <= 0 then FValue := nil else begin if FManager = nil then raise EEntityManagerNotSet.Create(T); FValue := FManager.Find<T>(FId); end; FLoaded := True; end; Result := FValue; end; procedure Proxy<T>.SetValue(const Value: T); begin FValue := Value; FLoaded := True; end;

Quadro 24 Implementao do Lazy Load no Proxy

3.4.5

Operacionalidade da implementao

Esta seo apresenta a operacionalidade do framework para construo de aplicaes em Delphi. Como o framework no disponibiliza uma interface grfica, a operacionalidade demonstrada atravs de trechos de cdigo fonte exemplificando a sua utilizao. Como o objetivo aqui puramente didtico, demonstrado um estudo de caso de desenvolvimento de uma aplicao hipottica: um aplicativo para gerenciar uma biblioteca de msicas e clipes armazenados em computador. A aplicao ser desenvolvida utilizando o padro de projeto MVC. Para este exemplo considera-se que a aplicao tenha sete classes, conforme o diagrama da Figura 25.

91

Figura 25 Diagrama de classes do estudo de caso

Para iniciar o desenvolvimento da aplicao, o primeiro passo abrir o ambiente Delphi e criar um novo projeto do tipo VCL Forms Application, conforme Figura 26. Deve-se salvar o cdigo fonte do projeto em uma pasta apropriada e importar para este projeto o cdigo fonte do framework, com todas as suas unidades, para que possam ser utilizadas ao longo da aplicao.

Figura 26 Criao de novo projeto no Delphi

Depois disto, implementa-se as classes de entidades, que representam o modelo do padro MVC. Estas classes so implementadas utilizando a linguagem Delphi normal,

92 declarando atributos e properties para manter os valores das entidades. Recomenda-se salvar as classes de entidades em uma pasta prpria para separar o modelo do restante da aplicao. A classe Artista, por exemplo, ficaria parecida com o cdigo mostrado na Figura 27. At aqui ainda no foram necessrios os componentes do framework.

Figura 27 Implementao da classe TArtista

Com as classes implementadas, comea-se a utilizar o framework. O prximo passo a anotao dos atributos customizados nas classes definidas. Para isto, deve-se adicionar a unidade MetadataEngine.Attributes na clusula uses da unidade onde est declarada a classe. Nesta etapa, deve-se definir um nome para a tabela onde ser persistida a classe, bem como os nomes e definies das colunas, e tambm a forma de gerao do Id, neste caso sequence. A implementao ficar conforme a Figura 28.

93

Figura 28 Classe TArtista mapeada no framework

A Figura 29 demonstra como ficaria a classe Obra. Foi utilizado o tipo especial
Nullable

nos

campos

que

no

so

obrigatrios,

importando

unidade

SpecialTypes.Nullable.

Tambm foi utilizado o tipo especial Proxy nos campos que

possuem carga tardia, importando a unidade SpecialTypes.Proxy. Nos campos que armazenam o lbum e o artista, foi anotada a Association com tipo de carregamento
ftLazy,

para que seus valores sejam carregados somente na primeira utilizao.

Como a estrutura Proxy requer que o valor seja acessado atravs da property Value, pode ser incmodo utilizar Obra.Artista.Value para acessar o objeto de Artista por todo o cdigo fonte da aplicao. Caso no haja tratamento especial a ser efetuado nos mtodos de acesso a este atributo, isto pode ser melhorado da seguinte forma: a) coloca-se as anotaes de Association e JoinColumn diretamente no atributo ao invs de na property; b) declara-se a property como sendo do tipo
TArtista

ao

invs

de

Proxy<TArtista>.

Nota-se que o atributo continua com o tipo Proxy<TArtista>;

c) implementa-se os mtodos de acesso, GetArtista e SetArtista, nos quais atribui-se ou obtm-se o valor atravs da property Value do Proxy. A classe Obra a classe raiz da hierarquia. Por isso, foi anotado o atributo

94 customizado Inheritance especificando a estratgia de herana. Neste caso, foi adotada a estratgia de tabela nica, isSingleTable. Ao utilizar esta estratgia, deve-se adicionar a anotao de um DiscriminatorColumn na classe raiz, e um DiscriminatorValue em cada classe filha no-abstrata.

Figura 29 Classe TObra mapeada no framework

A Figura 30 mostra a implementao dos mtodos de acesso da classe TObra.

95

Figura 30 Implementao dos mtodos de acesso da classe TObra

A Figura 31 mostra como ficaria a classe TAlbum. Nota-se a utilizao da anotao


ManyValuedAssociation

acima da property Obras que do tipo TList<TObra>. Como se

trata de uma associao bidirecional, pois tambm existe uma Association de TObra para
TAlbum,

foi informado o valor FAlbum para o parmetro MappedBy. Isto indica que o

framework deve utilizar a Column mapeada no atributo FAlbum da classe TObra como chave estrangeira tambm para esta associao.

96

Figura 31 Classe TAlbum mapeada no framework

A Figura 32 mostra como ficariam as classes TMusica e TClipe. Para cada uma delas, foi dado um nome diferente ao anotar o DiscriminatorValue. Este nome informado o nome que ficar gravado na coluna discriminadora no banco de dados, identificando a classe de cada registro da tabela. Alm disso, neste caso as associaes foram mapeadas como tipo de carregamento ftEager, para que o objeto de formato seja carregado juntamente com a msica ou clipe. No necessrio o atributo Id nestas classes porque o mesmo herdado da classe TObra, assim como a anotao de Sequence. As classes TFormatoMsica e TFormatoVdeo foram omitidas porque ficariam muito parecidas com a classe TArtista, seguindo o mesmo padro.

97

Figura 32 Classes TMusica e TClipe mapeadas no framework

Depois de definidos todos os mapeamentos nas classes de entidades, tem-se o modelo implementado. Pode-se ento implementar as vises e os controles que envolveriam as lgicas de negcio da aplicao. As vises seriam formulrios Delphi, implementados utilizando os componentes visuais da VCL. O framework no possui componentes para criao de telas, visto que seu objetivo fornecer a camada de persistncia. Para este exemplo, ser mostrada apenas uma interface com o usurio, a tela de cadastro de msicas. Esta interface poderia ser desenhada conforme a Figura 33. As demais telas de cadastro da aplicao, como cadastro de vdeos, de artistas, de lbuns, de formatos de msica e formatos de vdeos, poderiam seguir o mesmo padro.

98

Figura 33 Tela de cadastro de msicas

Neste formulrio existem campos de seleo de formato, artista e lbum. Os valores contidos nestes campos devem ser carregados utilizando o gerenciador de objetos, fazendo-se uma chamada para ObjectManager.FindAll. Para o carregamento, pode-se basear no exemplo mostrado na Figura 34.

Figura 34 Implementao do carregamento dos componentes da tela

A tela de cadastro de msicas deve utilizar um controlador para realizar a gravao das

99 msicas. Como sugesto de implementao, o evento OnClick do formulrio dispararia uma ao do controlador, passando como parmetro as informaes preenchidas na tela, encapsuladas em um objeto Musica auto-contido. A implementao ficaria conforme a Figura 35.

Figura 35 Implementao do boto de salvar msica

A Figura 36 mostra como ficaria a implementao do mtodo SalvarMusica do controlador. O mesmo faria uso do gerenciador de objetos do framework para salvar a msica no banco de dados atravs do mtodo Persist. Neste exemplo, o gerenciador de objetos criado e destrudo dentro do escopo de um mtodo, mas em transaes mais complexas o seu ciclo de vida pode e deve ser maior.

100

Figura 36 Implementao do mtodo para salvar msica no controlador

O framework no possui um gerenciamento completo de conexes, mas permite que a aplicao as gerencie como desejar, bastando que passe a conexo como parmetro na instanciao do gerenciador de objetos. Em aplicaes que possuem apenas uma conexo com um banco de dados, sugere-se a criao de uma classe nica de acesso conexo, seguindo o padro de projeto Singleton. A classe nica de acesso conexo poderia ser responsvel pela instanciao e configurao do objeto de conexo. Para a configurao do objeto de conexo, que implementa a interface IDBConnection, pode-se basear no exemplo da Figura 37. Nela, carrega-se a conexo a partir dos parmetros de conexo e conecta-se ao banco de dados. A conexo mostrada na figura feita com o SGBD Firebird. Como se pode ver no exemplo, o framework tambm no gerencia parmetros de conexo. Os mesmos devem ser gerenciados pela prpria aplicao. Logicamente, em um sistema de produo, os parmetros de conexo como usurio, senha e caminho da base de dados deveriam ser lidos de algum meio externo como arquivo criptografado ou registro do Windows, por exemplo.

101

Figura 37 Configurao do objeto de conexo

A aplicao tambm dever possuir telas de consulta das informaes cadastradas. Nestas telas, dever ser possvel alterar ou excluir os objetos cadastrados. No so mostradas estas telas, mas a Figura 38 mostra exemplos de implementao para alterar e excluir objetos. Note-se que como o mtodo Find genrico, no h a necessidade de converso de tipos de objetos. O gerenciador de objetos j devolve o objeto no tipo correto.

102

Figura 38 Exemplos de alterao e excluso de objetos

Com a aplicao pronta para ser compilada e executada, ainda falta a construo da base de dados, ou seja, a criao das tabelas. Esta tarefa pode ser feita utilizando o gerenciador de base de dados, disponibilizado pelo framework atravs da classe
TDatabaseManager.

A implementao pode ser feita conforme a Figura 39.

O mtodo BuildDatabase realiza a construo de todas as tabelas, chaves primrias, chaves nicas, chaves estrangeiras e sequences no banco de dados. Esta operao geralmente lenta e deve ser realizada apenas uma vez. Em uma aplicao local, pequena e monousurio, poderia ser executada na primeira vez que aberta a aplicao. J em um sistema clienteservidor, seria interessante compilar esta parte para um aplicativo de configurao em separado. Cabe ao desenvolvedor decidir o local onde esta implementao deve ser colocada de acordo com o caso.

103

Figura 39 Construo da base de dados

3.5

RESULTADOS E DISCUSSO

Nesta seo so apresentados os resultados obtidos da gerao de SQL e analisado o desempenho da persistncia de objetos em alguns testes realizados. Tambm feita uma comparao do framework com trabalhos correlatos.

3.5.1

Anlise do SQL gerado

A seguir so mostrados alguns testes feitos com o framework e o cdigo SQL que o mesmo gerou para cada teste. Ao final, so feitos comentrios sobre estes resultados. Estes testes foram realizados utilizando o SGBD Firebird, gerando SQL para este banco. A gerao de SQL para o MySQL teria apenas uma diferena: ao invs de sequences, ter-se-ia colunas do tipo auto-increment. Para todos os testes mostrados a seguir, consideram-se as classes de entidades mostradas no Quadro 25, as quais sumarizam em um nico cdigo todos os recursos

104 discutidos at o momento. Nota-se a auto-associao da classe TCliente atravs do atributo


FClienteCobranca. [Entity] [Table('CLIENTES')] [Sequence('SEQ_CLIENTES', 1, 1)] TCliente = class private [Id] [Column('CODIGO', [cpUnique, cpRequired])] FCodigo: LongInt; [Column('NOME', [cpRequired])] FNome: string; [Column('IDADE')] FIdade: Nullable<Integer>; [Column('NASCIMENTO')] FNascimento: Nullable<TDate>; [Column('ATIVO')] FIsAtivo: Nullable<Boolean>; [Association(ftEager, orOptional, ctCascadeAll)] [JoinColumn('CLIENTE_COBRANCA')] FClienteCobranca: Proxy<TCliente>; public // Getters e setters omitidos end; [Entity] [Table('NOTAS_FISCAIS')] [Sequence('SEQ_NOTAS_FISCAIS')] TNotaFiscal = class private [Id] [Column('CODIGO', [cpUnique, cpRequired])] FCodigo: LongInt; [Column('NUMERO', [cpUnique, cpRequired])] FNumero: Integer; [Association(ftEager, orOptional, ctCascadeAll)] [JoinColumn('CODIGO_CLIENTE')] FCliente: Proxy<TCliente>; function GetCliente: TCliente; procedure SetCliente(const Value: TCliente); public // Getters e setters omitidos end;

Quadro 25 Implementao das entidades utilizadas nos testes

3.5.1.1

Teste 1 Construo da base de dados

O primeiro teste foi feito para analisar a construo da base de dados a partir destas duas classes de entidades. O Quadro 26 mostra fielmente, incluindo as quebras de linha, o cdigo SQL gerado a partir da chamada do mtodo BuildDatabase do TDatabaseManager.

105

CREATE TABLE CLIENTES ( CODIGO INTEGER NOT NULL, NOME VARCHAR(255) NOT NULL, IDADE INTEGER, NASCIMENTO DATE, ATIVO CHAR(1), CLIENTE_COBRANCA INTEGER, CONSTRAINT PK_CLIENTES PRIMARY KEY (CODIGO)); CREATE TABLE NOTAS_FISCAIS ( CODIGO INTEGER NOT NULL, NUMERO INTEGER NOT NULL, CODIGO_CLIENTE INTEGER, CONSTRAINT PK_NOTAS_FISCAIS PRIMARY KEY (CODIGO), CONSTRAINT UK_NOTAS_FISCAIS UNIQUE (NUMERO)); ALTER TABLE CLIENTES ADD CONSTRAINT FK_CLIENTES_CLIENTES_CLIENTE_CO FOREIGN KEY (CLIENTE_COBRANCA) REFERENCES CLIENTES(CODIGO); ALTER TABLE NOTAS_FISCAIS ADD CONSTRAINT FK_NOTAS_FISCAIS_CLIENTES_CODIG FOREIGN KEY (CODIGO_CLIENTE) REFERENCES CLIENTES(CODIGO); CREATE GENERATOR SEQ_CLIENTES; CREATE GENERATOR SEQ_NOTAS_FISCAIS;

Quadro 26 SQL de construo da base de dados

Foram executados no total seis comandos SQL. Em primeiro lugar, o framework cria todas as tabelas correspondentes s entidades, sem as chaves estrangeiras. Depois so alteradas as tabelas, adicionando as chaves estrangeiras. Por fim, criadas as sequences. No SGBD Firebird, as sequences so chamadas de generators. As chaves estrangeiras no so criadas diretamente no comando create table porque em um caso de referncia mtua entre duas tabelas, o framework no saberia determinar qual tabela teria que ser criada por primeiro. Nota-se que o cdigo SQL gerado eficiente e possui uma boa legibilidade. Isto prov facilidade em casos onde necessrio monitorar ou analisar o SQL que est sendo gerado pelo framework.

3.5.1.2

Teste 2 Persistncia de objetos

O segundo teste foi feito para analisar o cdigo SQL gerado para persistncia de objetos. O Quadro 27 mostra o cdigo fonte que foi implementado na aplicao para a realizao deste teste.

106
NotaFiscal := TNotaFiscal.Create; NotaFiscal.Numero := 100; NotaFiscal.Cliente := TCliente.Create; NotaFiscal.Cliente.Nome := 'Nome do cliente'; NotaFiscal.Cliente.Nascimento := EncodeDate(2010, 10, 23); NotaFiscal.Cliente.IsAtivo := False; Manager.Persist(NotaFiscal);

Quadro 27 Implementao do teste de persistncia de objetos

Os comandos SQL gerados pelo framework para este teste, juntamente com seus parmetros, podem ser vistos no Quadro 28.
SELECT GEN_ID(SEQ_CLIENTES, 1) FROM RDB$DATABASE; INSERT INTO CLIENTES ( CODIGO, NOME, IDADE, NASCIMENTO, ATIVO, CLIENTE_COBRANCA) VALUES ( :A_CODIGO, :A_NOME, :A_IDADE, :A_NASCIMENTO, :A_ATIVO, :A_CLIENTE_COBRANCA); A_CODIGO = "1" (ftInteger) A_NOME = "Nome do cliente" (ftString) A_IDADE = NULL (ftInteger) A_NASCIMENTO = "23/10/2010" (ftDate) A_ATIVO = "False" (ftBoolean) A_CLIENTE_COBRANCA = NULL (ftInteger) SELECT GEN_ID(SEQ_NOTAS_FISCAIS, 1) FROM RDB$DATABASE; INSERT INTO NOTAS_FISCAIS ( CODIGO, NUMERO, CODIGO_CLIENTE) VALUES ( :A_CODIGO, :A_NUMERO, :A_CODIGO_CLIENTE); A_CODIGO = "1" (ftInteger) A_NUMERO = "100" (ftInteger) A_CODIGO_CLIENTE = "1" (ftInteger)

Quadro 28 Cdigo SQL gerado para persistncia de objetos

Verifica-se que o objeto que foi passado como parmetro para persistncia foi o objeto
NotaFiscal, Cliente.

porm o primeiro comando SQL gerado foi para persistncia do objeto

O framework tomou esta ao porque detectou que o objeto a ser persistido, estava associado com outro objeto que ainda no estava persistido. Ento este

NotaFiscal,

segundo objeto precisa ser persistido primeiro. Comparando-se o Quadro 27 com o Quadro 28, nota-se o quanto menos o framework permite ao programador escrever para produzir um cdigo de manuteno de notas e clientes.

107 3.5.1.3 Teste 3 Obteno de objetos

O terceiro teste foi feito para analisar o cdigo SQL gerado para obteno de objetos. O Quadro 29 mostra o cdigo fonte que foi implementado na aplicao para a realizao deste teste.
NotaFiscal := Manager.Find<TNotaFiscal>(1000);

Quadro 29 Implementao do teste de obteno de objetos

Os comandos SQL gerados pelo framework para este teste, juntamente com seus parmetros, podem ser vistos no Quadro 30.
SELECT A.CODIGO AS A_CODIGO, A.NUMERO AS A_NUMERO, B.CODIGO AS B_CODIGO, B.NOME AS B_NOME, B.IDADE AS B_IDADE, B.NASCIMENTO AS B_NASCIMENTO, B.ATIVO AS B_ATIVO, B.CLIENTE_COBRANCA AS B_CLIENTE_COBRANCA FROM NOTAS_FISCAIS AS A LEFT JOIN CLIENTES AS B ON (B.CODIGO = A.CODIGO_CLIENTE) WHERE A.CODIGO = :WHERE_A_CODIGO; WHERE_A_CODIGO = "1000" (ftInteger)

Quadro 30 Cdigo SQL gerado para obteno de objetos

Verifica-se que os objetos associados ao objeto NotaFiscal que possuem associao com carregamento ftEager so carregados juntamente com a nota fiscal em apenas uma requisio ao banco de dados. Isto feito atravs de junes do tipo inner join ou left
join.

Alm disso, verifica-se tambm que o framework adiciona aliases em todas as tabelas

da clusula from e campos da clusula select. Isto feito para garantir a unicidade dos campos no resultado do comando SQL, j que podem haver campos com mesmo nome em tabelas diferentes, ou ento a mesma tabela pode ser utilizada mais de uma vez no mesmo comando SQL. Por exemplo, se houver uma chave estrangeira de uma tabela para a prpria tabela, poder ser feito um join de uma tabela para ela mesma. Isto no gerar problemas desde que elas recebam diferentes aliases. Todas estas tcnicas aplicadas gerao do cdigo SQL de obteno de objetos fizeram diminuir um pouco a sua legibilidade, porm foram necessrias para garantir o seu funcionamento desde consultas mais simples at consultas mais complexas.

108 3.5.2 Anlise de desempenho

Foram realizados testes de desempenho com o framework, com finalidade de comparao entre diferentes formas de obteno e persistncia de objetos, bem como anlise de desempenho com cargas maiores. Na obteno de objetos, foram medidos os tempos com carregamento tardio e carregamento ansioso. Os testes foram realizados com o SGBD Firebird e as entidades que foram utilizadas so as classes TCliente e TNotaFiscal mostradas no Quadro 25. Na persistncia de objetos, todos os objetos de um mesmo teste foram persistidos dentro de um mesmo ciclo de vida do gerenciador de objetos. Sabendo-se que o gerenciador de objetos armazena cada objeto persistido no mapa de identidade, estes objetos foram acumulando durante cada teste, tendo no pior caso um mapa de identidade com 20.000 objetos mapeados. Na obteno de objetos, cada requisio foi feita para obter um objeto diferente, a fim de no utilizar o cache interno do framework. A Tabela 1 mostra os tempos medidos, em segundos.
Tabela 1 Medio de tempos de persistncia e obteno de objetos

Teste 1

Teste 2

Teste 3

Mdia 0,63 6,68 49,76 1,04 11,72 98,94 0,45 4,53 40,96 0,46 5,01 38,78 0,85 8,23 77,60 cresce

Persist de objetos avulsos 100 x 1 Cliente 0,40 0,56 0,92 1.000 x 1 Cliente 6,69 6,55 6,81 10.000 x 1 Cliente 49,92 48,06 51,30 Persist de objetos associados 100 x (1 NotaFiscal + 1 Cliente) 1,12 1,10 0,89 1.000 x (1 NotaFiscal + 1 Cliente) 13,53 9,29 12,33 10.000 x (1 NotaFiscal + 1 Cliente) 98,55 97,53 100,73 Find 100 x 1 Cliente 0,43 0,45 0,48 1.000 x 1 Cliente 4,81 4,44 4,35 10.000 x 1 Cliente 40,58 40,96 41,34 Find - Eager 100 x (1 NotaFiscal + 1 Cliente) 0,44 0,48 0,46 1.000 x (1 NotaFiscal + 1 Cliente) 6,06 4,60 4,37 10.000 x (1 NotaFiscal + 1 Cliente) 35,52 42,09 38,74 Find Lazy 100 x (1 NotaFiscal + 1 Cliente) 0,84 1,16 0,56 1.000 x (1 NotaFiscal + 1 Cliente) 7,09 8,69 8,92 10.000 x (1 NotaFiscal + 1 Cliente) 94,96 61,02 76,81 Como se pode constatar, em geral o tempo de persistncia dos objetos

linearmente. Ou seja, quanto maior o nmero de objetos a persistir, maior o tempo de execuo, proporcionalmente. O mesmo acontece com o tempo de obteno dos objetos. Verificou-se tambm que o tempo de persistncia de dois objetos associados em

109 geral duas vezes o tempo de persistncia de um objeto avulso. Isso indica que a associao entre os objetos no aumenta o tempo de persistncia no framework. Ou seja, associaes no geram uma sobrecarga perceptvel. Foram feitos testes comparativos entre estratgias de carregamento ftEager e ftLazy. Como se pode constatar, o carregamento de dois objetos com estratgia ftEager demora em mdia apenas 2,2% a mais do que o carregamento de apenas um objeto. J o carregamento dos mesmos objetos com estratgia ftLazy demora 88,9% a mais do que o carregamento de apenas um objeto, pois necessrio mais um acesso ao banco de dados. Com isto, verifica-se a importncia de recuperar objetos interligados em apenas um acesso ao banco sempre que possvel, desde que os objetos realmente sejam utilizados. Por outro lado, no interessante mapear todas as associaes como ftEager, pois desta forma um nico acesso ao banco carregaria uma quantidade grande demais de objetos, e isto pode deixar o SGBD sobrecarregado, aparentando estar travado inclusive para outros usurios. As associaes entre as entidades devem ser analisadas para determinar qual estratgia de carregamento mais apropriada para cada caso.

3.5.3

Comparaes com trabalhos correlatos

Para a comparao entre este trabalho e os frameworks correlatos, foi eleito um conjunto de caractersticas e funcionalidades a serem examinadas. Para tal, foram consultados os tpicos de ajuda de cada framework correlato, bem como suas documentaes. Tambm foram analisadas partes dos seus cdigos fontes. Os dados obtidos foram reunidos no Quadro 31. Embora os trabalhos correlatos possam ter outras funcionalidades importantes alm de persistncia e mapeamento objeto-relacional, so consideradas aqui apenas as caractersticas relevantes nesse contexto. A ferramenta de aplicao do padro DAO foi analisada parte por no ser um framework de persistncia.

110

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Caractersticas Este trabalho Hibernate Instant Objects Linguagem Delphi Win32 Java Delphi Win32 Verses suportadas 2010 1.4 a 1.6 5 a 2006 Ano da ltima verso oficial 2010 2010 2006 Suporta mapeamento de herana (quantas Sim (3) Sim (3) No estratgias?) Suporta mapeamento de associaes Sim Sim Sim Mapeamento com anotaes Sim Sim No Mapeamento com comentrios No No Sim Mapeamento com XML No Sim Sim Permite consultas polimrficas Sim Sim No Liberdade de herana na entidade raiz Sim Sim No Implementa Carga Tardia Sim Sim Sim Implementa Carga Ansiosa com Joins Sim Sim Sim Suporta tipos anulveis Sim Sim Sim No No Sim Orientado a Datasets (Ex: TTable, TQuery) Integrao nativa c/ controles de tela No No Sim Possui editor grfico de classes nativo No No Sim Possui linguagem especfica de consulta No Sim Sim Permite utilizar tipos comuns da linguagem Sim Sim No Constri a base de dados Sim Sim Sim Quadro 31 - Comparao entre caractersticas e funcionalidades dos frameworks

Tanto o Hibernate, segundo Bauer e King (2007, p. 192), quanto o framework desenvolvido neste trabalho implementam tcnicas de Mapeamento Objeto-Relacional, como mapeamento de herana e mapeamento de associaes, a fim de que a aplicao consiga utilizar com maior flexibilidade possvel os conceitos do paradigma orientado a objetos. Para cada uma destas tcnicas ainda possvel escolher entre um conjunto de estratgias. Porm, ambos os frameworks no possuem integrao nativa com componentes visuais para apresentao dos dados na interface grfica. Instant Objects (INSTANT OBJECTS, 2006) declarado pelos seus autores como um framework de persistncia de objetos, no sendo citado o conceito de mapeamento objetorelacional em sua definio, embora algumas tcnicas de mapeamento sejam utilizadas. Algumas de suas construes so orientadas a datasets, de forma a se encaixarem mais facilmente em alguns componentes da VCL de apresentao dos dados na tela, como DBEdit,
DBGrid,

entre outros. Por outro lado, ele carece de algumas caractersticas de um framework

puramente orientado a objetos como, por exemplo, consultas polimrficas. Um ponto positivo que Instant Objects suporta desde verses antigas como Delphi 5 at as mais atuais. Na verso que est sendo desenvolvida atualmente, o framework dever suportar Delphi 2010. Hibernate e Instant Objects possuem linguagens de consulta especficas. Hibernate disponibiliza a Hibernate Query Language (HQL) enquanto Instant Objects disponibiliza a Instant Query Language (IQL). As duas linguagens so inspiradas na linguagem SQL, onde

111 as tabelas so identificadas pelos nomes das classes. O framework desenvolvido neste trabalho no disponibiliza uma linguagem especfica para consultas. Esta funcionalidade sugerida como extenso. O framework desenvolvido neste trabalho e o Hibernate so frameworks pouco intrusivos, ou seja, evitam ao mximo alterar ou descaracterizar o cdigo fonte da aplicao para atingir seus objetivos. As classes de entidades no precisam descender de uma classe base do framework, o que possibilita que a entidade raiz de uma hierarquia tenha liberdade para descender de outra classe quando necessrio. Alm disso, os atributos podem usar tipos da prpria linguagem ao invs de tipos do framework. Desta forma, o cdigo fonte da aplicao torna-se mais desacoplado do framework. No framework Instant Objects, as classes de entidades precisam descender de uma classe base chamada TInstantObject, e os atributos precisam ser de tipos especiais como
TInstantString, TInstantDateTime

e TInstantReference, entre outros. Para minimizar o

impacto, o framework sugere que sejam criadas properties de tipos primitivos da linguagem e cujos getters e setters servem como adaptadores para os tipos do framework. No framework desenvolvido neste trabalho, algumas construes precisam utilizar tipos especiais, como Nullable e Proxy. Porm, o uso de tipos genricos nestas construes ajuda a minimizar a intruso j que, quando bem aplicados, afetam somente as classes de entidades. O resto do cdigo fonte da aplicao pode utilizar os atributos das entidades de forma transparente, sem preocupar-se com estas estruturas especiais, pois estas estruturas transpem o tipo primitivo genrico utilizado na declarao dos atributos. No Hibernate, o problema dos tipos anulveis resolvido com utilizao de objetos de valor ao invs de tipos primitivos. Usa-se a classe Integer ao invs do tipo int, por exemplo. A estrutura Proxy tambm no necessria no Hibernate porque o padro Lazy Load foi implementado utilizado orientao a aspectos, dispensando esta estrutura. Nota-se que as anotaes feitas com Atributos Customizados no framework desenvolvido neste trabalho so validadas em tempo de compilao pelo Delphi. Isto uma vantagem sobre mapeamentos baseados em XML ou comentrios, como o caso do Instant Objects, pois tais mapeamentos so validados somente em tempo de execuo pelo prprio framework. A ferramenta de aplicao do padro DAO de Sardagna (2007, p. 14) no um framework e sim de uma ferramenta de anlise e gerao de cdigo. Esta ferramenta adota um conceito comum que organizar uma camada de persistncia para aplicaes orientadas a objetos construdas em linguagem Delphi. Tal ferramenta tambm se baseia no uso do padro

112 de projeto DAO, e foi implementada em Delphi 2006. A ferramenta de aplicao do padro DAO, segundo Sardagna (2007, p. 64), foi implementada para suportar o SGBD Interbase, enquanto o framework do trabalho atual suporta Firebird e MySQL. Tal ferramenta analisa cdigos fonte de projetos com componente de acesso DBExpress. O framework do presente trabalho tambm utiliza DBExpress como componente padro de acesso, porm foi criada uma camada de independncia para que facilmente possam ser implementados adaptadores para outros componentes de acesso.

113 4 CONCLUSES

Os resultados obtidos com o desenvolvimento do framework foram bons. Foi possvel cumprir todos os requisitos propostos. Algumas tcnicas como mapeamento de herana, associaes, tipos anulveis e carregamento tardio tambm foram implementadas com sucesso, sem que tivessem sido definidos como requisitos funcionais. O objetivo principal do trabalho foi atendido, que era desenvolver um OPF em Delphi que utilize a tcnica de ORM para fornecer a camada de persistncia a uma aplicao. Acredita-se que esta camada de persistncia seja eficiente e transparente. Os objetivos especficos do trabalho tambm foram atendidos com sucesso. As ferramentas utilizadas foram adequadas para o desenvolvimento do trabalho. Os padres de projeto utilizados tambm foram adequados e acredita-se que tornaram o cdigo fonte do framework organizado e fcil de entender. Obteve-se produtividade com a explorao de recursos novos como tipos genricos, a nova API do RTTI e Atributos Customizados, disponveis na linguagem Delphi para Windows h menos de dois anos conforme Groves (2009). Tais recursos possibilitaram a construo de estruturas como Nullable e Proxy. Vrios tipos de aplicaes podem utilizar este framework como camada de persistncia, desde aplicaes pequenas com banco de dados embarcado at sistemas maiores que rodam em arquitetura cliente-servidor. Porm, para ser considerado prtico e eficiente na construo de grandes aplicaes, so necessrias certas adaptaes e extenses. O framework pode ser utilizado tambm para o desenvolvimento de middlewares para suportar arquiteturas mais elaboradas do que a cliente-servidor. Uma limitao que a nica plataforma suportada atualmente Windows. A proposta inicial deste trabalho previa resolver problemas de concorrncia com outras instncias da aplicao que interagem com o mesmo banco de dados. Porm, devido grande complexidade dos controles de transaes para tratar a concorrncia, optou-se por no implementar este suporte neste trabalho. Em aplicaes monousurio este problema simplesmente no existe. Em aplicaes cliente-servidor de pequeno porte pode-se executar a interao com o gerenciador de objetos vinculada com uma transao do SGBD. Ou seja, inicia-se uma transao no banco, depois se realiza toda a lgica que envolve a persistncia de uma s vez, depois se finaliza a transao. Desta forma, os objetos lidos ficaro bloqueados no banco enquanto a transao no for finalizada, impedindo modificaes concorrentes. Esta

114 tcnica, porm, pode deixar o sistema travado se houverem muitas transaes concorrentes, por isto no indicada para sistemas de grande porte. Alm disso, possvel resolver este problema como extenso, criando uma camada intermediria para tratar a concorrncia. Foi encontrada uma dificuldade ao implementar o padro de projeto Lazy Load. Estimava-se utilizar tcnicas de orientao a aspectos para aplicar este padro, mas o Delphi no suporta atualmente os mecanismos necessrios para tal. Elaborou-se ento uma soluo alternativa que se mostrou eficiente: a estrutura Proxy<T>. O resultado esperado foi alcanado com sucesso. Muitas funcionalidades do framework foram preparadas para serem estendidas, fazendo com que o projeto possa ser continuado, agregando mais funcionalidades com facilidade. Acredita-se que este trabalho contribua bastante para o desenvolvimento tecnolgico, inovando em termos de persistncia em Delphi para Windows. Algumas inovaes so a utilizao de anotaes para mapeamento e a disponibilizao de uma interface de persistncia fortemente orientada a objetos. Com isto, abre-se um leque de possibilidades para futuros trabalhos.

4.1

EXTENSES

Como sugestes para extenses a este trabalho sugerem-se: a) suporte a construo de consultas customizveis pelo usurio, com recursos como filtros, junes, ordenao e agrupamentos. Para tal, poderia ser desenvolvida uma API orientada a objetos ou ento uma linguagem especfica de consulta, semelhante HQL ou IQL; b) suporte a associaes muitos-para-muitos com ou sem classe associativa. Na primeira, o framework deve gerar uma tabela intermediria no banco de dados sem a necessidade de uma classe intermediria na aplicao; c) suporte a identificadores compostos por mais de um campo. A finalidade tornar o framework mais facilmente compatvel com bases de dados de sistemas legados; d) suporte a outros SGBDs de mercado, como Oracle, Microsoft SQL Server, PostgreSQL e IBM DB2, entre outros; e) centralizao das configuraes de conexo como usurio, senha, porta e caminho da base de dados no prprio framework, para que o framework possa gerenciar

115 transparentemente o objeto de conexo; f) controle avanado de transaes e sesses no gerenciador de objetos; g) suporte a mapeamento de campos de tipos especiais como BLOB, text, enumeraes e arrays; h) suporte ao mapeamento automtico de certos atributos como Column, para que seja possvel persistir uma classe sem mapear os atributos, visando a metologia Rapid Application Development (RAD) que faz parte da filosofia do Delphi; i) suporte a atualizao da estrutura de uma base de dados j criada pelo framework para uma nova verso, detectando as alteraes feitas nos mapeamentos das entidades e refletindo as mudanas no banco de dados atravs de comandos DDL; j) caso as prximas verses da linguagem Delphi venham a suportar orientao a aspectos, a implementao do padro Lazy Load nas associaes com estratgia de carregamento tardio pode ser aprimorada, eliminando a necessidade da estrutura Proxy; k) integrao com outros projetos como frameworks para gerao de telas. A ideia disponibilizar uma soluo mais completa para construo de diversas camadas da aplicao.

116 REFERNCIAS BIBLIOGRFICAS

BAUER, Christian; KING, Gavin. Java persistence with Hibernate. Greenwich: Manning Publications, 2007. BERNARDI, Diogo A. Tcnicas de mapeamento objeto relacional. SQL Magazine, Rio de Janeiro, v. 6, n. 40, p. 46-51, 2006. EMBARCADERO. The new memory manager in BDS 2006. [S.l.], 2006. Disponvel em: <http://edn.embarcadero.com/article/33416#1Introduction>. Acesso em: 27 out. 2010. EMBARCADERO. VCL overview. [S.l.], 2009. Disponvel em: <http://docwiki.embarcadero.com/RADStudio/en/VCL_Overview>. Acesso em: 6 out. 2010. EMBARCADERO. Attributes and RTTI. [S.l.], 2010. Disponvel em: <http://docwiki.embarcadero.com/RADStudio/en/Overview_of_Attributes>. Acesso em: 1 out. 2010. FOWLER, Martin. Padres de arquitetura de aplicaes corporativas. Traduo Mareci P. de Oliveira. Porto Alegre: Bookman, 2006. GAJIC, Zarko. A tour of Turbo Delphi IDE. [S.l.], [2006?]. Disponvel em: <http://delphi.about.com/od/turbodelphitutorial/ss/delphi_ide_tour_6.htm>. Acesso em: 2 mar. 2010. GAMMA, Erich et al. Padres de projeto: solues reutilizveis de software orientado a objetos. Traduo Luiz A. Meirelles Salgado. Porto Alegre: Bookman, 2000. GROVES, Malcolm. RTTI and attributes in Delphi 2010. [S.l.], 2009. Disponvel em: <http://www.malcolmgroves.com/blog/?p=476>. Acesso em: 26 mar. 2010. HEUSER, Carlos A. Projeto de banco de dados. 3. ed. Porto Alegre: Sagra Luzzatto, 2000. INSTANT OBJECTS. Instant Objects: object persistence framework. [S.l.], 2006. Disponvel em: <http://www.instantobjects.org/>. Acesso em: 26 mar. 2010. LEME, Ricardo R. Qual a diferena entre comandos DCL, DML e DDL. [S.l.], 2008. Disponvel em: <http://ricardoleme.blogspot.com/2008/06/qual-diferena-entre-comandos-dcldml-e.html>. Acesso em: 12 dez. 2010. MARTINS, Ivan J. RTTI: tpicos avanados. Clube Delphi, Rio de Janeiro, v. 1, n. 42, p. 611, [2003?].

117 MENEZES, Eduardo D. B. de. Princpios de anlise e projeto de sistemas com UML. 2. ed. totalmente rev. e atual. Rio de Janeiro: Campus, Elsevier, 2007. 369 p. MOURO, Rodrigo C. RTTI: conhea as novidades na RTTI do Delphi 2010. Clube Delphi, Rio de Janeiro, v. 6, n. 111, p. 104-121, 2009. MSDN. Nullable generic structure. [S.l.], 2006. Disponvel em: <http://msdn.microsoft.com/en-us/library/b3h38hb0(v=VS.80).aspx>. Acesso em: 4 out. 2010. QUICOLI, Paulo R. MVC: Model-View-Controller. Clube Delphi, Rio de Janeiro, v. 4, n. 90, p. 26-34, 2007. SARDAGNA, Marcelo. Ferramenta para aplicao do padro Data Access Object (DAO) em sistemas desenvolvidos com a linguagem de programao Delphi. 2007. 66 f. Trabalho de Concluso de Curso (Bacharelado em Cincia da Computao) Universidade Regional de Blumenau, Blumenau. SASSE, Erick. Convertendo arquivos DFM binrios para texto. [S.l.], 2005. Disponvel em: <http://www.ericksasse.com.br/convertendo-arquivos-dfm-binrios-para-texto/>. Acesso em: 6 abr. 2010. SILVA, Izalmo P.; SILVA, Samuel S. Desenvolvendo com Hibernate. Java Magazine, Rio de Janeiro, v. 4, n. 73, p. 113-114, 2009. SOARES, Srgio; BORBA, Paulo. AspectJ: programao orientada a aspectos em Java. Recife, 2002. Disponvel em: <http://www.cin.ufpe.br/~phmb/papers/AspectJTutorialSBLP2002.pdf>. Acesso em: 20 out. 2010. TIGRIS. TortoiseSVN: project home. [S.l.], 2010. Disponvel em: <http://tortoisesvn.tigris.org>. Acesso em: 27 out. 2010. TIOBE SOFTWARE. TIOBE programming community index for March 2010. [S.l.], 2010. Disponvel em: <http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html>. Acesso em: 26 mar. 2010. TROTTIER, Alain. Java 2 developer exam cram 2. [S.l.]: Que Publishing, 2004.

Vous aimerez peut-être aussi