Beruflich Dokumente
Kultur Dokumente
FACULDADE DE ENGENHARIA
CINCIA DA COMPUTAO
Itana
2014
UNIVERSIDADE DE ITANA
FACULDADE DE ENGENHARIA
CINCIA DA COMPUTAO
Orientador:
Itana
2014
Este trabalho foi julgado adequado para obteno da aprovao na disciplina Trabalho
de Concluso do Curso de Cincia da Computao da Faculdade de Engenharia da Universidade de Itana.
Aprovado por:
Dedico este trabalho primeiramente minha famlia e amigos, por estarem sempre presentes
nos momentos em que preciso e por me apoiarem durante todo este tempo. Dedico tambm aos
meus amigos de classe e professores, que contriburam para tornar estes ltimos 4 anos em uma
das pocas inesquecveis da minha vida.
Agradecimentos
Resumo
As Linguagens Orientadas a Objetos em conjunto com os Sistemas Gerenciadores de
Bancos de Dados Relacionais (SGBDs) so considerados padres no desenvolvimento de
Sistemas de Informao Empresarial. Embora o uso destas duas tecnologias em conjunto mostre resultados satisfatrios, encontra-se dificuldade em efetuar a transio de
informaes entre os seus contextos de representao de dados.
Para efetuar a transio de informaes necessrio desenvolver componentes de
software especficos para cada classe que represente dados que necessitam ser persistidos
no banco de dados, o que se mostra uma tarefa repetitiva e propensa a erros. Com o
objetivo de amenizar este problema, foram criadas as Bibliotecas de Mapeamento Objeto
Relacional (ORMs), que so componentes de software capazes de automatizar o processo
de transio de dados entre os dois contextos.
Devido a limitaes nos recursos de reflexo e insero de metadados oferecidos pela
linguagem C++, o desenvolvimento de solues ORM para esta linguagem se mostra uma
tarefa bastante complexa. A maioria das solues implementadas apresenta interfaces de
configurao complexas, alm de utilizar recursos da linguagem que promovem o aumento
do nvel de acoplamento do cdigo.
Este trabalho prope o desenvolvimento de uma biblioteca ORM para a linguagem
C++, onde so implementados mecanismos prprios de reflexo e insero de metadados a
partir da utilizao dos novos recursos propostos pela especificao C++11. A biblioteca
utiliza vrios componentes oferecidos pelo framework Qt para auxiliar em tarefas como
comunicao com banco de dados e extenso de tipos nativos.
Palavras-chave: Orientao a Objetos, SGBD, C++, ORM
Abstract
The Object Oriented Languages combined with the Relational Database Management
Systems (RDBMs) are considered a pattern in Enterprise Information Systems (EIS)
development. Although their use show good results, is difficult to perform the information
transition between their contexts of data representation.
To perform the information transition it is necessary to develop specific software
components for each class that represents data persisted in the database, task that shows
itself repetitive and error prone. With the goal of ease this problem, we created the Object
Relational Mapping (ORM) libraries, software components that automates the process of
data transition between the two contexts.
Due to limitations in the C++ reflection and metadata insertion features, the development of ORM solutions for this language is a very complex task. The existent solutions
present complex configuration interfaces, besides using language resources that increase
the coupling level of code.
This paper proposes the development of a ORM library for the C++ language, using
own mechanisms of reflection and insertion of metadata based on the features of the
C++11 specification. The library uses many components offered by the Qt framework to
help in tasks like communication with the database and extension of native types.
Keywords: Object Oriented, RDBMS, C++, ORM
Glossrio
API
ORM
SGBD
SQL
EIS
Sumrio
1 Introduo
2 Fundamentao Terica
2.1
Orientao a Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2
2.2.1
Reflexo ou Introspeco . . . . . . . . . . . . . . . . . . . . . . . .
2.2.2
2.2.2.1
Listas de Inicializao . . . . . . . . . . . . . . . . . . . .
2.2.2.2
2.2.2.3
2.2.2.4
Inferncia de Tipos . . . . . . . . . . . . . . . . . . . . . . 14
2.2.2.5
Programao Funcional . . . . . . . . . . . . . . . . . . . 16
2.2.2.6
2.3
O Framework Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.4
2.5
O PostgreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.6
2.7
3 Trabalhos Relacionados
3.1
31
Sumrio
viii
3.2
QxORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.3
ODB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.4
Hibernate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4 A Biblioteca ORM4Qt
35
4.1
Arquitetura em Camadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.2
Camada Objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.3
4.2.1
4.2.2
Camada de Armazenamento . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5 Testes
5.1
5.2
44
Ambiente de Testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.1.1
5.1.2
A Classe Documento . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.2.1.1
5.2.1.2
5.2.1.3
5.2.2
A Classe IRepository . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6 Concluso
56
Referncias Bibliogrficas
58
Lista de Figuras
2.1
2.2
2.3
Janela no GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.4
2.5
Janela no Mac Os . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.6
4.1
4.2
4.3
5.1
Lista de Algoritmos
10
11
12
13
14
15
16
17
18
19
20
21
LISTA DE ALGORITMOS
11
22
23
24
Captulo 1
Introduo
Vivemos em uma era onde os sistemas informatizados deixaram de ser vistos como meras
ferramentas de automatizao de tarefas. Onde o software desempenha papel fundamental
no planejamento estratgico e desempenho de atividades nas grandes empresas. A proliferao de Sistemas de Informao Empresarial (Enterprise Information Systems
- EIS) se mostra cada vez mais notria. Estes sistemas so caracterizados por sua alta
complexidade e por trabalharem com gerenciamento constante de dados [Lhotka, 2009].
As Linguagens Orientadas a Objetos se tornaram um padro consolidado no
desenvolvimento destes sistemas. Devido sua capacidade de abstrair representaes de
entidades do mundo real como componentes de software, estas linguagens permitem aos
arquitetos e engenheiros de software terem uma viso de alto nvel durante o planejamento
e especificao do sistema [Nierstrasz, 1989].
Os Sistemas Gerenciadores de Bancos de Dados Relacionais (SGBDs) so o
meio consolidado para armazenamento de dados estruturados. Eles permitem o armazenamento de informaes de tal forma que estas podem ser manipuladas atravs de comandos
em linguagem SQL ou Structured Query Language. Esta linguagem permite executar
operaes de insero, remoo, edio e gerao de consultas de alta complexidade nos
dados armazenados [Barnes, 2007].
Apesar de as linguagens orientadas a objetos serem utilizadas em conjunto com os
SGBDs no desenvolvimento de sistemas, a forma de representao dos dados nos dois
contextos diferente. No contexto orientado a objetos, as informaes so vistas sobre
uma perspectiva comportamental, onde os componentes do software so importantes no
somente pelos dados que eles contm, mas pela habilidade de se comunicar com outros
componentes para compartilhar estas informaes e executar aes sobre elas. J no
1 Introduo
contexto dos SGBDs, as informaes so vistas sobre uma perspectiva estrutural, onde o
objetivo principal das entidades armazenar os dados e representar suas relaes da forma
mais otimizada possvel. No existe a preocupao em se definir o comportamento das
informaes. Devido a essa diferena de representao de dados entre os dois contextos,
existe a necessidade de converso ou mapeamento durante a transio entre eles. A
gerao de cdigo para mapeamento se mostra uma tarefa repetitiva e propensa a erros.
Com o objetivo de otimizar a utilizao das linguagens orientadas a objetos em conjunto com os SGBDs surgiu o conceito de Biblioteca de Mapeamento Objeto Relacional ou ORM (Object Relational Mapping). Este tipo de biblioteca tem como objetivo
automatizar as tarefas de mapeamento dos dados entre os dois contextos. Sua utilizao promove maior produtividade e reduo da complexidade envolvida em tarefas de
manuteno e modificao do cdigo [Barnes, 2007]. Neste trabalho proposto o desenvolvimento de uma biblioteca ORM para a linguagem C++. O framework Qt
utilizado como auxlio para comunicao com os SGBDs, e extenso dos tipos nativos da
linguagem C++.
Os demais captulos deste trabalho encontram-se organizados da seguinte maneira:
O Captulo 2 apresenta os conceitos bsicos para a correta compreenso do trabalho. O
Captulo 3 apresenta os trabalhos correlatos. O Captulo 4 apresenta as caractersticas
da biblioteca desenvolvida no trabalho, bem como a metodologia e as tcnicas utilizadas
no seu desenvolvimento. O Captulo 5 apresenta a metodologia de testes utilizada para
validao e comparao da biblioteca desenvolvida com duas bibliotecas existentes no
mercado. E, por fim, o Captulo 6 apresenta a concluso do trabalho, onde so descritos
os resultados encontrados e sugestes de trabalhos futuros.
Captulo 2
Fundamentao Terica
2.1
Orientao a Objetos
Linguagem interpretada com tipagem dinmica baseada em scripts muito utilizada em programao
1
2
3
4
5
6
7
c l a s s Pessoa {
private :
s t r i n g m_nome ;
s t r i n g m_sobrenome ;
public :
s t r i n g nomeCompleto ( ) { r e t u r n m_nome + m_sobrenome ; }
}
relao sua definio no importa em qual contexto ele seja utilizado [Nierstrasz, 1989].
Em algumas linguagens como JAVA o polimorfismo implcito, ou seja, na pergunta
anterior se desejssemos que a implementao da classe pai fosse executada, isso no seria
possvel. J em outras linguagens como C++, o polimorfismo definido explicitamente
atravs do uso de palavras-chave da linguagem.
Ao analisar todas estas caractersticas citadas, percebemos que as linguagens orientadas a objetos promovem a criao de entidades de software bem descritivas. Isto facilita
sua utilizao por arquitetos e engenheiros de software, que podem visualizar os elementos
envolvidos no desenvolvimento com uma viso de mais alto nvel. Talvez esta seja a razo
da vasta aceitao e utilizao destas linguagens. Neste trabalho utilizada a linguagem
orientada a objetos C++, a qual detalhada na seo 2.2.
2.2
A linguagem C++ uma linguagem orientada a objetos criada em 1980 por Bjarne
Stroustrup. uma linguagem compilada, ou seja, o cdigo criado pelo desenvolvedor
convertido atravs de um programa denominado compilador para uma linguagem nativa
de uma plataforma alvo, gerando um ou mais arquivos executveis. Estes arquivos so
passveis de execuo direta na plataforma sem a interveno de ferramentas externas
[Bueno, 2002].
A linguagem C++ foi construda com base na linguagem C. Inicialmente o cdigo
escrito em C++ era traduzido para C e compilado com compiladores desta linguagem.
Com o aumento da complexidade de implementao das caractersticas e funcionalidades que foram surgindo na linguagem ao longo de sua existncia, surgiram compiladores
especficos para C++ [Brokken and Kubat, 2014].
Dentre as caractersticas da linguagem esto a capacidade de definio de classes,
utilizao de herana mltipla, utilizao de polimorfismo, gerenciamento de memria
controlado pelo desenvolvedor e compatibilidade com cdigos escritos em C. Outra importante caracterstica da linguagem a sua no portabilidade, ou seja, o cdigo gerado
para uma plataforma (sistema operacional e/ou hardware especfico) geralmente no
compatvel com outras plataformas. Devido a isso, a linguagem possui uma biblioteca
padro bem reduzida, no oferecendo por exemplo bibliotecas de comunicao em rede e
utilizao de banco de dados [Bueno, 2002].
2.2.1
Reflexo ou Introspeco
Algumas vezes nos deparamos com a tarefa de desenvolver rotinas que dependem do
conhecimento da estrutura de um objeto qualquer. Problemas como escreva uma funo
que mostre o nome dos atributos de um objeto ou escreva uma funo que armazene em
um arquivo o valor de todos os atributos de um objeto so alguns exemplos de rotinas
deste tipo. nestes momentos que a utilizao de mecanismos de introspeco ou
reflexo se torna til.
Estes mecanismos consistem na disponibilizao por parte da linguagem de programao de estruturas que permitem analisar a especificao de um objeto e acessar seus
recursos, tudo em tempo de execuo. Desta forma podemos escrever rotinas genricas
que podem trabalhar com qualquer tipo de objeto para executar diversos tipos de tarefas,
como listar os atributos de um objeto, acessar e alterar o valor destes atributos, listar os
mtodos de um objeto e at mesmo execut-los [Lhotka, 2009].
Geralmente as linguagens hbridas e as interpretadas oferecem mtodos de reflexo
completos, pois as informaes da estrutura dos objetos so utilizadas pelas prprias
mquinas virtuais e pelos interpretadores em tempo de execuo. Neste caso, j que a
informao j est presente e formatada durante a execuo, basta a linguagem criar
mecanismos de disponibilizao dos mesmos [Lhotka, 2009].
J no cenrio das linguagens compiladas a situao bem diferente. No h a necessidade de gerao de informaes sobre estruturas de objetos para o cdigo ser executado,
2
Um conjunto de bibliotecas que implementam funcionalidades frequentemente utilizadas no desenvolvimento de software, como por exemplo, acesso a banco de dados e comunicao em redes.
visto que o programa gerado em cdigo nativo [Gregoire, 2014]. A linguagem C++ do
tipo compilada, portanto, tambm sofre com a falta de mecanismos de reflexo nativos.
2.2.2
A linguagem C++ foi criada para ser uma linguagem de propsito geral, com o objetivo
principal de apresentar mecanismos para programao com alto nvel de abstrao, porm,
ao mesmo tempo sem privar o desenvolvedor da capacidade de acessar rotinas e recursos
de baixo nvel. Sendo assim possvel obter programas de alto desempenho em diversas
plataformas diferentes [Brokken and Kubat, 2014].
Para a linguagem ser utilizada em mltiplas plataformas necessrio que exista um
compilador que suporte a criao de programas a partir da anlise de cdigo fonte em
C++ para cada plataforma. Para evitar variaes na implementao destes compiladores
existe uma especificao oficial de todo o conjunto de recursos oferecidos pela linguagem
bem como sua sintaxe [Brokken and Kubat, 2014]. Esta especificao mantida pela ISO
(International Organization for Standardization).
As linguagens de programao evoluem com a passar do tempo. Em alguns momentos
preciso acrescentar novos recursos para alinhar a linguagem com os padres atuais,
outras vezes necessrio melhorar recursos existentes ou at mesmo corrigir erros na
especificao [Brokken and Kubat, 2014].
A especificao da linguagem C++ passou por uma grande atualizao em 1998 (conhecida como C++98), seguida de algumas correes em 2003 (especificao conhecida
como C++03). Desde ento a especificao no sofria alteraes significativas, o que
levou a linguagem a ficar um pouco desatualizada de acordo com os conceitos que foram
surgindo ao longo dos anos. At que em meados de 2011 um comit de especialistas
comeou a agir com o intuito de trazer novos recursos para a linguagem. Isso levou
publicao da especificao C++11 no final do ano de 2011 e projeo de atualizaes
da linguagem para os anos de 2014 e 2017, especificaes conhecidas como C++14 e
C++17 [Brokken and Kubat, 2014].
A figura 2.1 mostra a linha do tempo da evoluo da especificao da linguagem C++.
Nela possvel perceber a grande concentrao de tarefas previstas para os anos entre
2014 e 2017. Durante a finalizao deste trabalho (novembro de 2014) a especificao
C++14 est prevista para ser publicada em breve3 .
3
Listas de Inicializao
Mecanismo presente na linguagem C++ que permite agrupar estruturas dentro de um espao de
resoluo de nomes comum. utilizado para evitar conflitos de nomes entre estruturas.
10
// I n i c i a l i z a o de v e t o r e s
i n t v e t o r [ ] = { 1 , 2 , 3 , 4 } ; // V l i d o em C++98
// I n i c i a l i z a o de c o n t a i n e r s
v e c t o r <i n t > l i s t a 1 = { 1 , 2 , 3 , 4 } ; // V l i d o em C++11
5
6
7
8
9
// D e c l a r a o da c l a s s e Container <T>
template <typename T> c l a s s C o n t a i n e r {
C o n t a i n e r ( c o n s t i n i t i a l i z e r _ l i s t <T> & l i s t ) ;
};
10
11
12
13
2.2.2.2
Classe presente na biblioteca padro de C++, e que implementa uma estrutura de lista de elementos
utilizando reas de memria contguas.
1
2
3
4
5
6
// D e c l a r a o de um v e t o r
i n t vetor [ ] = {1 , 2 , 3 , 4 , 5};
// Acesso s e q u e n c i a l v i a n d i c e
f o r ( i n t i = 0 ; i < 5 ; ++i ) {
c o u t << v e t o r [ i ] << e n d l ;
}
7
8
9
10
11
12
13
// D e c l a r a o de um c o n t a i n e r
v e c t o r <i n t > c o n t a i n e r = { 1 , 2 , 3 , 4 , 5 } ;
// Acesso s e q u e n c i a l v i a n d i c e
f o r ( i n t i = 0 ; i < c o n t a i n e r . s i z e ( ) ; ++i ) {
c o u t << c o n t a i n e r [ i ] << e n d l ;
}
1
2
3
4
5
6
7
8
9
10
11
12
// D e c l a r a o de um c o n t a i n e r
v e c t o r <i n t > c o n t a i n e r = { 1 , 2 , 3 , 4 , 5 } ;
// Acesso s e q u e n c i a l v i a i t e r a d o r e s do t i p o c o n s t a n t e s
f o r ( v e c t o r <i n t > : : c o n s t _ i t e r a t o r i = c o n t a i n e r . c b e g i n ( ) ;
i != c o n t a i n e r . cend ( ) ; ++i ) {
c o u t << i << e n d l ;
}
// Acesso s e q u e n c i a l v i a i t e r a d o r e s do t i p o no c o n s t a n t e s
f o r ( v e c t o r <i n t > : : i t e r a t o r i = c o n t a i n e r . b e g i n ( ) ;
i != c o n t a i n e r . end ( ) ; ++i ) {
c o u t << i << e n d l ;
}
11
12
Na especificao C++11 foi adicionada uma variao do lao de repetio for que
basicamente uma simplificao das tcnicas 1 e 2 descritas anteriormente. Considerando
que temos um grupo de elementos do tipo T armazenados em uma estrutura (vetor ou
container ) com uma instncia chamada elementos, podemos navegar sobre os elementos
desta instncia utilizando um trecho de cdigo no formato for (T e : elementos) {...}.
Neste caso, o cdigo contido entre as chaves ser executado uma vez para cada elemento
contido em elementos, onde a varivel e assume o valor de cada um destes elementos
[Gregoire, 2014].
Esta nova variao pode ser utilizada tanto com vetores quanto com estruturas do
tipo container, e tambm possvel navegar sobre os elementos em modo somente leitura.
No trecho de cdigo 5 demonstrada a utilizao desta nova sintaxe de diferentes formas.
1
2
3
4
5
6
7
8
9
10
// D e c l a r a o de um v e t o r
i n t vetor [ ] = {1 , 2 , 3 , 4 , 5};
// Acesso s e q u e n c i a l nova s i n t a x e , com c p i a
f o r ( i n t i : v e t o r ) { // i c o p i a o v a l o r de cada e l e m e n t o
c o u t << i << e n d l ;
}
// Acesso s e q u e n c i a l nova s i n t a x e , com r e f e r n c i a
f o r ( i n t &i : v e t o r ) { //No h c p i a de v a l o r e s
c o u t << i << e n d l ;
}
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// D e c l a r a o de um c o n t a i n e r
v e c t o r <i n t > c o n t a i n e r = { 1 , 2 , 3 , 4 , 5 } ;
// Acesso s e q u e n c i a l nova s i n t a x e , com c p i a
f o r ( i n t i : c o n t a i n e r ) { // i c o p i a o v a l o r de cada e l e m e n t o
c o u t << i << e n d l ;
}
// Acesso s e q u e n c i a l nova s i n t a x e , com r e f e r n c i a
f o r ( i n t &i : c o n t a i n e r ) { //No h c p i a de v a l o r e s
c o u t << i << e n d l ;
}
// Acesso s e q u e n c i a l nova s i n t a x e , somentel e i t u r a com r e f e r n c i a
f o r ( c o n s t i n t &i : c o n t a i n e r ) {
c o u t << i << e n d l ;
}
2.2.2.3
13
A manipulao de ponteiros uma tarefa complexa, que deve ser feita com muito
cuidado. Uma tentativa de acesso a uma regio de memria invlida pode gerar problemas
graves durante a execuo do programa. Para evitar este tipo de problema, uma boa
prtica consiste em invalidar ou anular ponteiros durante a sua inicializao e quando
o seu uso chegou ao fim (o que acontece por exemplo quando desalocamos a regio de
memria apontada por ele) [Gregoire, 2014].
Para anular um ponteiro simplesmente atribumos a ele o valor 0. Porm, na maioria
dos ambientes de desenvolvimento, temos a presena de uma macro chamada NULL que
utilizada no local do valor 0 durante a anulao de um ponteiro para fins de legibilidade.
Esta metodologia pode levar a comportamentos inesperados do cdigo durante a execuo, visto que a macro expandida para o valor inteiro 0 durante a compilao. Se
temos duas funes com o mesmo nome, onde uma recebe um ponteiro como parmetro
e a outra recebe um nmero inteiro, ao executar esta funo passando a macro NULL,
a verso que recebe o nmero inteiro ser executada, gerando assim um comportamento
inesperado.
Com o objetivo de resolver este problema a especificao C++11 prev a existncia
do identificador nullptr para ser utilizado com o significado de ponteiro nulo. Ento se
no mesmo problema citado executssemos a funo passando nullptr como parmetro,
a verso que recebe o ponteiro ser executada [Gregoire, 2014]. O exemplo citado pode
ser observado no trecho de cdigo 6.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
v o i d main ( )
{
f u n c a o (NULL) ; // Executa f u n c a o ( i n t v a l o r )
f u n c a o ( n u l l p t r ) ; // Executa f u n c a o ( c h a r v a l o r )
}
2.2.2.4
14
Inferncia de Tipos
1
2
3
4
// D e c l a r a uma l i s t a de i n t e i r o s
v e c t o r <i n t > v e t o r = new v e c t o r <i n t >() ;
//Obtm um i t e r a d o r para a l i s t a d e c l a r a d a
v e c t o r <i n t > : : i t e r a t o r i t e r = v e t o r >b e g i n ( ) ;
1
2
3
4
// D e c l a r a uma l i s t a de i n t e i r o s
auto v e t o r = new v e c t o r <i n t >() ;
//Obtm um i t e r a d o r para a l i s t a d e c l a r a d a
auto i t e r = v e t o r >b e g i n ( ) ;
Utilizado para declarar variveis constantes, ou seja, que no podem ser usadas para modificar valores.
Neste contexto se refere ao modificador para declarao de variveis do tipo referncia na linguagem
C++.
7
1
2
3
4
15
c o n s t i n t& c o n s t R e f ( i n t& v a l o r )
{
return valor ;
}
5
6
7
8
9
10
11
i n t main ( )
{
int valor = 10;
//O t i p o d e d u z i d o ( i n t ) e no ( c o n s t i n t &)
auto numero = c o n s t R e f ( v a l o r ) ;
}
1
2
3
4
c o n s t i n t& c o n s t R e f ( i n t& v a l o r )
{
return valor ;
}
5
6
7
8
9
10
11
12
13
i n t main ( )
{
int valor = 10;
//O t i p o d e d u z i d o ( c o n s t i n t &)
d e c l t y p e ( c o n s t R e f ( v a l o r ) ) numero = c o n s t R e f ( v a l o r ) ;
// S i m p l i f i c a o p r o p o s t a na C++14
d e c l t y p e ( auto ) num = c o n s t R e f ( v a l o r ) ;
}
Mecanismo presente na linguagem C++ que permite o desenvolvimento de cdigo que pode trabalhar
com diferentes tipos de dados. muito utilizado na construo de estruturas do tipo container.
2.2.2.5
16
Programao Funcional
1
2
3
4
5
6
7
8
c l a s s Exemplo {
public :
c o n s t s t r i n g getTexto ( )
{ r e t u r n m_texto ; }
// . . .
private :
s t r i n g m_texto ;
};
9
10
11
c o n s t s t r i n g getTexto ( )
{ r e t u r n s t r i n g ( "Exemplo de f u n o . " ) ; }
12
13
14
15
16
17
18
i n t main ( )
{
// P o n t e i r o para f u n o
c o n s t s t r i n g ( f u n c a o ) ( ) = &getTexto ;
// P o n t e i r o para mtodo
c o n s t s t r i n g ( Exemplo : : metodo ) ( ) = &Exemplo : : getTexto ;
19
// U t i l i z a n d o o p o n t e i r o de f u n a o
c o u t << f u n c a o ( ) << e n d l ;
// U t i l i z a n d o o p o n t e i r o de mtodo
Exemplo ex ;
c o u t << ( ex . metodo ) ( ) << e n d l ;
20
21
22
23
24
25
f u n c a o = metodo ; // I n v l i d o
metodo = f u n c a o ; // I n v l i d o
26
27
28
17
1
2
3
4
5
6
7
8
18
c l a s s Exemplo {
public :
c o n s t s t r i n g getTexto ( )
{ r e t u r n m_texto ; }
// . . .
private :
s t r i n g m_texto ;
};
9
10
11
c o n s t s t r i n g getTexto ( )
{ r e t u r n s t r i n g ( "Exemplo de f u n o . " ) ; }
12
13
14
15
16
17
18
19
20
21
22
23
24
i n t main ( )
{
// Declarando c o n t a i n e r u n i f i c a d o
f u n c t i o n <c o n s t s t r i n g ( )> f u n c a o = n u l l p t r ;
// A t r i b u i n d o e u t i l i z a n d o uma f u n o
f u n c a o = getTexto ;
c o u t << f u n c a o ( ) << e n d l ;
// A t r i b u i n d o e u t i l i z a n d o um mtodo
Exemplo e ;
f u n c a o = bind (&Exemplo : : getTexto , &e ) ; // r e l a c i o n a i n s t n c i a
c o u t << f u n c a o ( ) << e n d l ;
}
19
invlida de memria. A captura pode ser feita especificando cada varivel que
queremos capturar, como por exemplo no trecho [a, &b] capturamos a varivel a
por valor e b por referncia. Ou podemos capturar todas as variveis do contexto
utilizando [=] para capturar todas as variveis por valor ou [&] para capturar
por referncia. Caso no seja necessrio capturar variveis, utilizamos colchetes sem
contedo, assim [] [Brokken and Kubat, 2014].
2) Lista de parmetros (Parameter specification): onde especificada a lista de
parmetros que a expresso lambda recebe. A sintaxe a mesma utilizada na
definio de prottipos de funes e mtodos. Por exemplo no trecho (int a, char
b) dizemos que a expresso recebe um nmero inteiro que ser referenciado no
corpo da expresso como a e tambm recebe um caractere que ser referenciado
como b [Brokken and Kubat, 2014].
3) Mutable specification: Por padro, variveis capturadas por valor so tratadas dentro do bloco de execuo da expresso como do tipo constante, ou seja, no podemos modificar seus valores. Caso utilizemos o modificador mutable elas no
sero mais tratadas como do tipo constante, ento poderemos manipular os valores
copiados no bloco de execuo da expresso [Brokken and Kubat, 2014].
4) Especificao do tipo de retorno (Return type specification): Neste ponto devemos especificar o tipo de dado que ser retornado pela expresso lambda. Caso a
expresso no retorne valores ou o tipo do valor retornado pode ser deduzido pelo
compilador, podemos omitir esta parte [Brokken and Kubat, 2014].
5) Bloco de execuo (Lambda body ): Consiste do bloco de cdigo que ser executado quando a expresso for utilizada. Assim como a lista de parmetros, este trecho de definio segue a mesma sintaxe da definio de funes e mtodos comuns.
Podem ser utilizadas quaisquer construes vlidas para blocos de execuo na linguagem C++. importante ressaltar tambm que no h um limite de tamanho
para o bloco, porm expresses lambda geralmente so bem concisas e simplificadas,
ocupando poucas linhas. Caso a expresso comece a ficar muito grande e complexa,
talvez seja melhor definir uma funo comum para que possa ser reutilizada por
outros componentes do programa [Brokken and Kubat, 2014].
No trecho de cdigo 13 temos um exemplo de definio de uma expresso lambda
com o mesmo prottipo utilizado nos exemplos anteriores. Note que a expresso pode ser
20
1
2
3
4
// Exemplo de e x p r e s s o lamda
f u n c t i o n <c o n s t s t r i n g ( )> lambda = [ ] ( ) { r e t u r n s t r i n g ( "Exemplo . " ) ; } ;
// Executando a e x p r e s s o
c o u t << lambda ( ) << e n d l ;
2.2.2.6
Um dos maiores desafios enfrentados por desenvolvedores que utilizam a linguagem C++
consiste na garantia da liberao de blocos de memria alocados dinamicamente a partir
do uso de ponteiros. Sempre que alocamos uma regio de memria a partir do uso do
operador new, temos que garantir que em algum ponto do cdigo aquela regio ser
liberada, tarefa que deve ser realizada explicitamente com o uso do operador delete
[Brokken and Kubat, 2014].
Regies de memria alocada que no so liberadas, iro persistir marcadas como utilizadas durante todo o fluxo de execuo do programa, causando assim um efeito de utilizao extra de memria indevida tambm conhecido como memory leak [Gregoire, 2014].
Com o objetivo de evitar este tipo de problema, a especificao C++11 prev a
criao de ponteiros inteligentes ou smart pointers, que so basicamente estruturas que
simulam o funcionamento de um ponteiro comum, porm adicionando mecanismos de
gerenciamento de memria. Do ponto de vista de padres de projeto, um smart pointer
seria um proxy para a interface de ponteiros comuns [Brokken and Kubat, 2014].
A especificao C++11 define a presena de trs smart pointers, sendo eles:
1) unique_ptr: Este ponteiro tm basicamente as mesmas caractersticas de um ponteiro comum. A nica diferena que ele automaticamente libera a regio de memria apontada por ele quando ele deletado ou quando o escopo de sua utilizao
chega ao fim [Gregoire, 2014].
2) shared_ptr: Este ponteiro possui uma funcionalidade um pouco mais avanada.
Ele mantm um contador interno que armazena a quantidade de referncias que
existem para a regio de memria apontada por ele, ou seja, ele armazena quantas instncias do tipo shared_ptr se encontram ativas no momento para aquela
21
regio de memria. O contador incrementado quando o ponteiro copiado e decrementado quando instncias de ponteiros so deletadas ou perdem escopo. Somente
quando o contador chegar a zero, ou seja, quando no existir mais nenhuma cpia do ponteiro original ativa, a regio de memria ser automaticamente liberada
[Gregoire, 2014].
3) weak_ptr: Este ponteiro utilizado para testar se uma instncia de shared_ptr
ainda vlida (ainda no foi desalocada), e caso o for, permite efetuar uma cpia
desta instncia para acessar a regio de memria apontada [Gregoire, 2014].
O trecho de cdigo 14 demonstra a utilizao dos trs tipos de smart pointers descritos anteriormente. Nele so alocados dois espaos de memria para armazenar dados
do tipo inteiro dentro de um escopo de execuo delimitado por chaves. Assim que o
escopo finalizado, ambos os ponteiros desalocam a regio de memria apontada por
eles automaticamente. No cdigo tambm mostrado como utilizar um weak_ptr para
verificar se um shared_ptr ainda vlido a partir da utilizao do mtodo lock que
retorna uma cpia deste segundo ponteiro no caso de validao ou retorna nullptr caso
contrrio.
1
2
// D e c l a r a um weak_ptr sem i n i c i l i z a o
weak_ptr<i n t > wptr ;
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Abertura de e s c o p o
{
// D e c l a r a um shared_ptr
shared_ptr<i n t > s p t r = shared_ptr<i n t >(new i n t ( 1 0 ) ) ;
// D e c l a r a um unique_ptr
unique_ptr<i n t > u p t r = unique_ptr<i n t >(new i n t ( 1 0 ) ) ;
// I n i c i a l i z a o weak_ptr
wptr = s p t r ;
// Testa s e memria a i n d a no f o i d e s a l o c a d a
i f ( auto p t r = wptr . l o c k ( ) )
{
// Cdigo s e r executado , p o i s s p t r a i n d a no perdeu e s c o p o
c o u t << p t r << e n d l ;
}
} //Fim do escopo , s p t r e u p t r s o d e s a l o c a d o s
19
20
21
22
23
24
25
// Testa s e memria a i n d a no f o i d e s a l o c a d a
i f ( auto p t r = wptr . l o c k ( ) )
{
//No s e r executado , p o i s s p t r perdeu e s c o p o
c o u t << p t r << e n d l ;
}
2.3 O Framework Qt
2.3
22
O Framework Qt
2.3 O Framework Qt
23
2.3 O Framework Qt
24
2.4
25
Assim como as linguagens orientadas a objetos so consideradas um padro para desenvolvimento de software, os Sistemas Gerenciadores de Bancos de Dados Relacionais ou
SGBDs so considerados um padro para armazenamento estruturado de informaes
[Barnes, 2007].
Os SGBDs utilizam um modelo de persistncia denominado modelo relacional,
que se baseia no uso de tabelas e colunas. As tabelas representam entidades, ou um
grupo de informao a ser armazenado, e podem se relacionar com outras tabelas para
promover regras de armazenamento. As colunas representam as caractersticas da entidade
armazenada. Neste modelo, quando armazenamos um registro, ele acrescentado como
uma linha em uma ou mais tabelas relacionadas. Nas tabelas, pode ser aplicado o conceito
de unicidade dos registros armazenados, atravs da definio de um conjunto de colunas
que deve representar uma combinao de valores nica dentre os registros armazenados.
Este conjunto de colunas define o que chamamos de chave primria da tabela ou, em
ingls, primary key [Barnes, 2007].
A definio de chaves primrias nas tabelas criadas permite a criao de relaes entre
elas atravs do uso de referncias entre suas chaves. A referncia em uma tabela para uma
chave primria de outra tabela conhecida como chave estrangeira ou, em ingls, foreign key [Barnes, 2007]. Na figura 2.6 temos um exemplo de definio de duas tabelas,
uma representando registros de pessoas e outra de telefones. Elas esto relacionadas, de
modo que um registro de telefone pertence a uma pessoa. Este comportamento obtido
atravs da definio da chave estrangeira TelefoneId na tabela Pessoa, que se refere
chave Id na tabela Telefone.
Uma das funcionalidades mais importantes apresentada pelos SGBDs a capacidade
de aplicao de rotinas complexas de pesquisa usando a linguagem SQL. Esta linguagem
define um conjunto de operaes que permite executar inseres, modificaes, remoo e
busca de registros armazenados em um SGBD [Barnes, 2007]. Talvez esta funcionalidade
seja a causa de sua grande utilizao e aceitao. Neste trabalho utilizado o SGBD
PostgreSQL (ver seo 2.5).
2.5 O PostgreSQL
26
2.5
O PostgreSQL
O PostgreSQL um SGBD de cdigo aberto, e com licena de uso gratuita para qualquer
pessoa sobre qualquer propsito. Ele pode ser utilizado, modificado e redistribudo livremente. Este SGBD derivado do projeto POSTGRES desenvolvido na Universidade de
Berkeley na Califrnia no ano de 1986. Por ser um software de cdigo aberto desenvolvido
em comunidade, ele conhecido por ser pioneiro na adio de novas funcionalidades, e se
mantm sempre atualizado em relao aos conceitos e especificaes da linguagem SQL
[PostgreSQL, 2014].
2.6
A princpio, os programas trabalham com dados em memria principal, que voltil. Isto
, ao desligarmos o equipamento todos os dados so perdidos. Devido a isso, necessitamos
de algum mecanismo de persistncia, ou seja, que permita a gravao de dados importantes
em memria secundria, no voltil [Barnes, 2007].
A combinao mais comumente utilizada para alcanar este cenrio o uso de linguagens orientadas a objetos para desenvolver o software e o uso de SGBDs para armazenar
os dados gerados pelo software [Bauer and King, 2005]. Porm, os dados no contexto
orientado a objetos e no contexto relacional so estruturados de maneiras diferentes, portanto precisamos realizar uma converso ou mapeamento dos dados durante a transio
de contextos.
27
Quando estamos trabalhando com classes simples (no compostas por membros de
outras classes), o mapeamento segue uma lgica simples. Podemos criar uma correspondncia entre a classe e sua respectiva tabela, onde os atributos da classe so mapeados para
colunas de uma tabela. Porm quando comeamos a utilizar mecanismos mais avanados
da orientao a objetos como herana e composio, o mapeamento entre os contextos se
torna mais complexo [Barnes, 2007].
Mesmo quando temos um cenrio onde o mapeamento simples, precisamos gerar
cdigo de converso. As linguagens de programao fornecem bibliotecas ou APIs 11 que
permitem a comunicao com SGBDs atravs do envio de comandos em linguagem SQL
[Barnes, 2007]. O cdigo gerado para executar a transio de dados entre os dois contextos
geralmente segue a seguinte sequncia de passos:
1. Carregar um driver de comunicao com o SGBD utilizado e abrir a conexo;
2. Criar um objeto que permita a montagem de cdigo SQL;
3. Enviar o comando para o SGBD para que seja executado;
4. Recuperar e processar os dados ou resposta gerados pelo SGBD;
5. Liberar os recursos alocados para execuo da tarefa, como por exemplo fechar a
conexo com SGDB.
No trecho de cdigo 15 temos um esboo de como estas etapas so realizadas utilizando
a linguagem C++ em conjunto com o mdulo QtSql do framework Qt (ver seo 2.3) e
comunicando com o SGBD PostgreSQL (ver seo 2.5).
1
2
3
4
5
6
A utilizao deste tipo de cdigo se torna repetitiva, visto que temos que executar
estes passos para todas as classes que armazenam dados utilizando SGBDs. Este tipo
de comportamento indesejado, pois diminui a produtividade do desenvolvimento, alm
11
28
do fato de que tarefas repetitivas tem grande potencial de gerarem erros. Outro grande
problema que encontramos que os comandos em linguagem SQL variam entre os SGBDs,
portanto ao mudar o SGBD utilizado pelo programa, temos de reescrever os comandos
SQL utilizados. Este outro fator com grande potencial de gerao de erros, alm de
diminuir a flexibilidade do software, tornando, em alguns casos, invivel a mudana de
SGBD [Barnes, 2007].
Para otimizar a combinao do uso de linguagens de programao orientadas a objetos
em conjunto com SGBDs, surgiu o conceito de Biblioteca de Mapeamento Objeto
Relacional ou ORM (Object Relational Mapping ), assunto abordado na seo 2.7.
2.7
29
permitem gerar o cdigo de mapeamento e at mesmo gerar o cdigo das classes a partir da anlise de um banco de dados existente. Esta funcionalidade conhecida como
Mapeamento Reverso ou Engenharia Reversa [Barnes, 2007].
As bibliotecas ORM divergem bastante na forma de implementao e funcionalidades
disponibilizadas. Isso se deve principalmente ao fato da divergncia de recursos entre
as prprias linguagens de programao em que so implementadas. Porm uma deciso
comum a ser tomada no desenvolvimento de uma biblioteca ORM em qualquer linguagem, a definio do ponto de partida para obteno das informaes de mapeamento
[Barnes, 2007]. Os paradigmas mais utilizados so:
1) Orientado a metadados: Neste paradigma, o desenvolvedor informa a estrutura das
entidades envolvidas no software que devem ser mapeadas atravs de alguma fonte
externa, como um arquivo XML. Neste arquivo so informados metadados12 sobre
as entidades nos dois contextos, o que permite a biblioteca ORM criar o cdigo de
definio das classes e do cdigo de mapeamento. Neste modelo podemos utilizar
um banco de dados j existente, ou a biblioteca ORM pode constru-lo a partir
da anlise dos metadados. A vantagem deste paradigma a abstrao total da
gerao de cdigo de manipulao do banco de dados. E sua grande desvantagem
a limitao de edio do cdigo gerado pela biblioteca. Os cdigos das classes
mapeadas sero gerados automaticamente pela biblioteca e no podero ser editados
pelo desenvolvedor [Barnes, 2007].
2) Orientado aplicao: Neste paradigma o desenvolvedor deve escrever o cdigo das
classes de todo o programa normalmente, porm sem se preocupar com as operaes
de persistncia. Aps a definio das classes, a biblioteca ORM, atravs da anlise
do cdigo e opcionalmente metadados, consegue criar o cdigo de persistncia.
possvel utilizar um banco de dados existente ou a biblioteca pode constru-lo. A
vantagem deste paradigma a total abstrao da gerao de cdigo de manipulao
do banco de dados, e sua grande desvantagem a alta complexidade de desenvolver
o mecanismo de anlise do cdigo escrito pelo desenvolvedor para inferir informaes de mapeamento. A definio deste mecanismo pode influenciar bastante no
desempenho final da aplicao que utiliza a biblioteca ORM [Barnes, 2007].
3) Orientado ao banco de dados: Neste paradigma o desenvolvedor deve primeiramente criar o banco de dados. Ento a biblioteca ORM auxiliada por metadados
12
Informaes complementares sobre outro conjunto de dados. Podem ser utilizados, por exemplo, para
descrever a estrutura destes.
30
consegue gerar o cdigo das classes a serem mapeadas e das operaes de persistncia. A grande desvantagem deste paradigma a no abstrao do conhecimento de
banco de dados, visto que o desenvolvedor deve primeiramente definir a estrutura
da base de dados a ser utilizada. Outra desvantagem o desenvolvedor no ter a
permisso de modificar o cdigo das classes mapeadas pela biblioteca ORM. Sua
vantagem consiste no melhor controle da definio da estrutura da base de dados
sendo utilizada [Barnes, 2007].
As bibliotecas de mapeamento mais robustas possuem a possibilidade de operar nos
trs paradigmas citados. Em alguns casos, elas ainda permitem que o desenvolvedor tenha
controle dos trs componentes principais citados pelos paradigmas, ou seja, o desenvolvedor pode definir o cdigo das classes a serem mapeadas, os metadados e construir o banco
de dados a ser utilizado, deixando para a biblioteca ORM somente a tarefa de adicionar
o cdigo de persitncia [Barnes, 2007].
Existe ainda o conceito de transparncia, que aplicado a bibliotecas que utilizam o
paradigma orientado aplicao. Uma biblioteca ORM transparente quando no requer
que classes implementem interfaces, ou sigam um modelo especfico de cdigo para serem
mapeadas [Barnes, 2007]. Estas bibliotecas seguem a filosofia de que as classes envolvidas
no software no precisam saber como, porque ou quando elas sero persistidas, ou seja,
elas devem se comportar como classes ordinrias ou comuns.
Analisando as principais funcionalidades que as bibliotecas ORM possuem, podemos
perceber que elas promovem uma melhoria considervel de produtividade (economia de
tempo de desenvolvimento) alm de diminuir a complexidade do desenvolvimento de sistemas que lidam com gerenciamento constante de dados persistidos em bancos de dados
relacionais [Barnes, 2007].
Captulo 3
Trabalhos Relacionados
3.1
3.2 QxORM
32
1) Camada de objetos (Object Layer ): Camada responsvel por prover uma interface simples para definio de classes a serem mapeadas e seus metadados, alm de
trafegar dados entre os objetos mapeados e a camada de persistncia. Esta camada
a nica acessvel diretamente pelo desenvolvedor.
2) Camada de persistncia (Storage Layer ): Camada responsvel por abstrair a comunicao com o SGBD, provendo rotinas de persistncia, concorrncia, recuperao de erros e execues de pesquisas no banco de dados. Esta camada no
diretamente acessvel pelo desenvolvedor.
O modelo definido pode ser aplicado em diversas linguagens pelo fato de no se aproveitar de recursos especficos de determinadas linguagens, porm devido a isso ele exige
um trabalho adicional do desenvolvedor ao reimplementar mtodos de diversas interfaces
definidas. Em alguns momentos, o desenvolvedor deve explicitamente executar funes
de consulta e ajuste de valores de atributos em suas classes trocando informaes com
o framework para permitir a execuo de tarefas no banco de dados [Zhang, 2004]. Isso
ocorre devido a biblioteca no definir um mecanismo de listagem e acesso s estruturas
internas dos objetos mapeados.
Neste trabalho o modelo de Zhang utilizado como base para a implementao de
uma biblioteca ORM para C++, porm com alguns ajustes como a definio de uma
interface de anotaes para definies de mapeamento, e a capacidade de mapeamento
de classes arbitrrias, sem a necessidade de herana de uma classe especfica (biblioteca
transparente).
3.2
QxORM
QxORM uma biblioteca ORM de cdigo aberto desenvolvida para ser utilizada em
conjunto com o framework Qt. Ela utiliza vrios mdulos deste framework como auxlio
na execuo das tarefas de mapeamento, como por exemplo, o mdulo QtSql para realizar
interaes com os SGBDs. Foi criada em 2003 e mantida pelo Engenheiro de software
Lionel Marty [Marty, 2014].
Esta biblioteca segue o paradigma orientado a aplicao, e transparente, ou seja,
permite o mapeamento de classes arbitrrias. Para mapear uma classe, o desenvolvedor deve inserir algumas marcaes na definio da classe, e implementar um mtodo
utilizando funes especficas para registros de informaes das classes e atributos a se-
3.3 ODB
33
3.3
ODB
ODB uma biblioteca ORM desenvolvida para ser utilizada com a linguagem C++.
uma biblioteca de cdigo aberto e mantida pela empresa Code Synthesis. Ao contrrio
da biblioteca QxOrm, a ODB no foi desenvolvida para ser utilizada especificamente em
conjunto com um framework ou outra biblioteca, mas sim com a linguagem C++ pura.
Para ser utilizada em conjunto com o framework Qt, por exemplo, a biblioteca disponibiliza um recurso chamado profile, que atua como uma espcie de plugin adicional que
pode ser acoplado a biblioteca para habilitar seu uso em conjunto [Synthesis, 2013].
Mesmo quando utilizada com profiles, a biblioteca utiliza mecanismos prprios para
acesso a banco de dados e construo de sentenas em linguagem SQL. As informaes de mapeamento so especificadas atravs do uso de diretivas de pr-processamento
pragma 1 . Estas informaes so analisadas por um compilador disponibilizado em
conjunto com a biblioteca, que gera ento cdigo em C++ com os comandos para realizar
tarefas de persistncia [Synthesis, 2013].
A biblioteca utiliza o paradigma orientado a aplicao com uma abordagem transparente, pois no obriga o desenvolvedor a implementar interfaces ou aplicar herana nas
classes a serem mapeadas para o banco de dados. Seu sistema de insero de metadados
bem parecido com o sistema de anotaes, porm estes metadados somente so acessveis
pelo seu compilador externo [Synthesis, 2013].
Esta biblioteca tambm utilizada durante testes de usabilidade e de configurao do
ambiente de desenvolvimento no Captulo 5.
1
3.4 Hibernate
3.4
34
Hibernate
O Hibernate uma das bibliotecas ORM escritas em JAVA, mais conhecidas atualmente.
um projeto de cdigo aberto mantido e desenvolvido pela empresa Red Hat. Esta
biblioteca uma das bibliotecas ORM mais completas, sendo pioneira na implementao
de vrios mecanismos de otimizao. Ela utiliza um paradigma orientado a aplicao e a
insero de metadados de mapeamento pode ser feita a partir da utilizao de arquivos
XML, ou a partir da utilizao do mecanismo de anotaes presente na linguagem JAVA
[Bauer and King, 2005].
A biblioteca capaz de mapear classes que utilizam mecanismos de herana e composio, alm de ter a capacidade de a partir da anlise das classes mapeadas e dos metadados,
criar o banco de dados equivalente. Seu mecanismo de anotaes a inspirao principal
do desenvolvimento deste trabalho, pois tal mecanismo traz um nvel de facilidade enorme
na configurao dos dados de mapeamento, e at ento poucas bibliotecas voltadas para
a linguagem C++ apresentam algo semelhante [Bauer and King, 2005].
Captulo 4
A Biblioteca ORM4Qt
Este recurso permite que uma classe ou mtodo global externo acesse os componentes privados de
uma classe.
36
de mapear somente classes simples, ou seja, que contm somente atributos escalares e no
utilize herana. Posteriormente, ela poder ser estendida para suportar o mapeamento de
classes que utilizem mecanismos mais avanados da orientao a objetos.
Das bibliotecas ORM existentes para o cenrio abordado, a QxOrm e a ODB so as
que mais se aproximam das caractersticas citadas, portanto elas so utilizada em testes ao
final do desenvolvimento que comparam a configurao do ambiente de desenvolvimento
para utilizao das bibliotecas, a facilidade em utilizao dos mecanismos de configurao
de mapeamento e a facilidade em migrao de cdigo legado.
Nas prximas sees sero detalhados os mecanismos utilizados para o desenvolvimento, bem como a arquitetura utilizada.
4.1
Arquitetura em Camadas
37
4.2
Camada Objeto
Para que seja possvel realizar o mapeamento, a biblioteca ORM deve ser capaz de conhecer e acessar a estrutura interna das classes a serem mapeadas. Existem basicamente dois
limitadores que dificultam alcanar este cenrio na linguagem C++. O primeiro deles
consiste na possibilidade de o desenvolvedor limitar o acesso estrutura interna atravs
das diretivas de proteo oferecidas pela linguagem durante a definio das classes. A
biblioteca ORM precisa ter acesso de leitura e escrita nos atributos das classes sendo mapeadas, porm em geral eles so mantidos com permisso de acesso privado, onde somente
podem ser acessados diretamente de dentro da classe.
O segundo deles o baixo suporte da linguagem a mecanismos de reflexo. Antes de
acessar os atributos das classes a biblioteca deve saber quais so os atributos que a classe
contm, entretanto em seu atual estado, a linguagem oferece somente informaes bsicas
38
sobre os objetos, como por exemplo o nome de sua classe. No trecho de cdigo 16 temos
um exemplo da obteno do nome da classe de um objeto em tempo de execuo. Na
linha 1 criado um objeto da classe Pessoa, e na linha 2 capturado o nome da classe
deste objeto e exibido no console. A sada gerada por este programa quando compilado
no compilador que acompanha o Visual Studio 2013 o texto class Pessoa.
1
2
4.2.1
Quando os atributos das classes so declarados com acesso pblico, a biblioteca ORM
pode acess-los diretamente, porm este cenrio no normalmente utilizado pelos desenvolvedores e a utilizao da biblioteca impor tal cenrio uma caracterstica indesejvel
e que poderia diminuir sua aceitao no mercado. Para resolver este problema foi pressuposto que todos os atributos a serem acessados nas classes a serem mapeadas estaro com
acesso privado, ou seja, s podem ser acessados de dentro das classes. Com isso em mente
podemos tambm definir que somente poderemos acessar os atributos das classes atravs
do uso de um intermediador que componha a estrutura da classe, ou mais precisamente
um mtodo que compe a interface da classe.
A primeira ideia que vem em mente utilizar mtodos acessadores (popularmente
conhecidos como mtodos get e set) criados pelos desenvolvedores, porm temos
alguns limitadores que dificultam a sua utilizao. Um deles que no podemos assumir
que para todo atributo existem mtodos acessadores, pois podem existir atributos somente
leitura ou cujo valor controlado internamente na classe. Outro limitador a ausncia
de padronizao do prottipo dos mtodos acessadores, pois estes mtodos podem ser
definidos com uma quantidade varivel de parmetros. Alm disso, a linguagem C++
permite a criao de variaes destes mtodos atravs da modificao do tipo de parmetro
e/ou retorno (ponteiro, referncia ou por valor), alm do uso do modificador const na
declarao de mtodos de leitura.
Devido a estas caractersticas, o uso de ponteiros genricos para mtodos, por exemplo,
no poderia ser utilizado, pois teramos que variar a definio dos ponteiros de acordo com
39
// Mtodos g e t
int get () ;
int get () ;
i n t &g e t ( ) ;
int get () const ;
int get () const ;
i n t &g e t ( ) c o n s t ;
// Mtodos s e t
void s e t ( i n t valor ) ;
v o i d s e t ( i n t &v a l o r ) ;
void s e t ( i n t valor ) ;
void s e t ( const i n t valor ) ;
v o i d s e t ( c o n s t i n t &v a l o r ) ;
void s e t ( const i n t valor ) ;
1
2
3
4
5
6
7
8
9
10
40
c l a s s Class
{
public :
s t d : : f u n c t i o n <i n t ( )> getLambda ( )
{
r e t u r n [ & ] ( ) > i n t { r e t u r n t h i s >v a l o r ; } ;
}
private :
int valor ;
};
Algoritmo 18: Retornando uma expresso lambda para acesso de atributo privado
atributo. Na linha 4 temos a definio do mtodo que retorna a expresso lambda e na
linha 6 a sua criao e retorno. A sintaxe de criao de expresses lambda pode parecer
estranha inicialmente, porm com o decorrer do seu uso ela se torna prtica e simples. O
mtodo criado pela biblioteca no retorna uma simples lista de expresses lambda, mas
um objeto que alm de armazenar as expresses, armazena metadados, como veremos no
prximo tpico.
4.2.2
Como no temos um mecanismo nativo para obter conhecimento sobre as estruturas das
classes sendo mapeadas em momento de execuo, temos que criar algum mecanismo
que permita a criao destas informaes. Uma maneira de fazer isto seria criar um
analisador de cdigo, que a partir da leitura dos arquivos de definio das classes geraria
estas informaes automaticamente. Esta soluo tem a grande vantagem de gerar as
informaes em momento de compilao e agir de forma transparente. Entretanto, a
implementao de tal soluo uma tarefa bastante complexa, alm de seu uso promover
uma quebra no fluxo padro de compilao de programas, pois o desenvolvedor ter que
inserir a execuo deste analisador no fluxo de compilao antes da execuo do prprio
compilador. Outro problema, que somente a informao das estruturas das classes no
suficiente para realizar o mapeamento, precisamos de informaes a mais, como o nome
das colunas equivalentes aos atributos.
A soluo proposta neste trabalho consiste em inserir um mtodo nas classes mapeadas que retorne uma estrutura com todos os metadados necessrios para o mapeamento,
ampliando a ideia exposta na seo 4.2.1. Para organizar as informaes a serem retornadas foi criada uma hierarquia de classes de armazenamento de metainformaes,
baseada em uma classe chamada Reflect. Esta classe permite o registro de tuplas do
41
tipo chave e valor, chamadas de tags, que podem ser recuperadas atravs de funes
de sua interface. A partir desta classe so definidas as classes Property e Class.
A primeira responsvel por descrever as informaes relativas a um atributo de uma
classe, e prov mtodos para acesso a este atributo em uma instncia de classe utilizando
o mecanismo de expresses lambda citado anteriormente. A segunda classe responsvel
por descrever as informaes relativas a uma classe. Ela contm uma lista de objetos de
descrio de atributos, alm de permitir a definio de informaes adicionais atravs da
insero de tags. Na imagem 4.2 temos um diagrama de classe simplificado que demonstra
a hierarquia criada.
42
1
2
3
4
5
c l a s s Classe
{
private :
int inteiro ;
std : : s t r i n g texto ;
6
7
ORM4QT_BEGIN
8
9
10
11
12
13
14
ORM4QT_END
};
4.3
Camada de Armazenamento
43
A segunda classe a SQLProvider que define uma interface para gerao de comandos em linguagem SQL para a execuo das tarefas de persistncia de objetos. Ela
utiliza os objetos de reflexo disponibilizados pela camada objeto para construir sentenas
de acordo com a instncia de objeto a ser persistida. Esta interface deve ser implementada
para cada tipo de SGBD que se deseja utilizar, desta forma a adio de suporte da biblioteca para diversos SGBDs se torna uma tarefa mais simples. A classe Repository utiliza
uma implementao desta interface para gerar os comandos necessrios para execuo de
suas tarefas.
Captulo 5
Testes
Aps a implementao da biblioteca ORM4Qt foi necessrio definir um modelo de testes que pudesse ser aplicado a ela em conjunto com outras bibliotecas j existentes. O
objetivo deste modelo o de avaliar o nvel de usabilidade da biblioteca sob o ponto de
vista do desenvolvedor, isto , avaliar a facilidade de uso da biblioteca no ambiente de
desenvolvimento utilizado.
O modelo de testes escolhido foi o desenvolvimento de uma aplicao simples chamada Minhas Apostilas, que consiste de um programa que permite o armazenamento de
arquivos no formato PDF em uma base de dados do SGBD PostgreSql. Alm do arquivo,
o aplicativo armazena um pequeno grupo de informaes referentes a ele, como nome,
descrio e data de alterao.
Com o intuito de testar a integrao das bibliotecas utilizadas com o ambiente de
desenvolvimento baseado no framework Qt, o aplicativo utiliza alguns recursos adicionais
do framework para a construo de uma interface grfica (mdulos QtGui e QtWidgets)
e para realizao de tarefas de forma assncrona (mdulo QtConcurrent). Alm disso,
o aplicativo foi desenvolvido de forma totalmente portvel, sendo testado nos sistemas
operacionais Ubuntu 14.04 e Microsoft Windows 8.1, ambos com a arquitetura 64 bits.
Foram escolhidas duas bibliotecas ORM existentes para serem comparadas com a
biblioteca desenvolvida, sendo elas, a ODB e a QxOrm. Ambas bibliotecas foram descritas
no Captulo 4. Nas prximas sees so detalhados os ambientes de desenvolvimento
utilizados para realizao dos testes e descritas as funcionalidades presentes no programa
Minhas Apostilas.
5.1
45
Ambiente de Testes
5.1.1
http://qt-project.org
http://www.codesynthesis.com/products/odb/
46
5.1.2
http://boost.org
http://postgresql.org
5.2
47
5.2.1
A Classe Documento
Para representar os documentos gerenciados pelo programa, foi criada uma classe chamada
Documento, cuja definio pode ser vista no trecho de cdigo 20. A classe definida
contm 6 atributos que armazenam os dados referentes a cada arquivo gerenciado pelo
aplicativo:
Cdigo: Consiste de um identificador numrico nico associado com cada arquivo armazenado. armazenado internamente no atributo privado m_codigo e acessvel
atravs dos mtodos codigo (leitura) e setCodigo (escrita);
1
2
3
4
5
6
c l a s s Documento
{
public :
// C o n s t r u t o r e d e s t r u t o r
Documento ( ) ;
v i r t u a l ~Documento ( ) ;
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Mtodos a c e s s a d o r e s
qlonglong codigo () const ;
v o i d s e t C o d i g o ( c o n s t q l o n g l o n g &c o d i g o ) ;
QString nome ( ) c o n s t ;
v o i d setNome ( c o n s t QString &nome ) ;
QString d e s c r i c a o ( ) c o n s t ;
v o i d s e t D e s c r i c a o ( c o n s t QString &d e s c r i c a o ) ;
QDateTime u l t i m a A l t e r a c a o ( ) c o n s t ;
v o i d s e t U l t i m a A l t e r a c a o ( c o n s t QDateTime &u l t i m a A l t e r a c a o ) ;
quint16 versao () const ;
v o i d s e t V e r s a o ( c o n s t q u i n t 1 6 &v e r s a o ) ;
QByteArray a r q u i v o ( ) c o n s t ;
v o i d s e t A r q u i v o ( c o n s t QByteArray &a r q u i v o ) ;
21
22
23
24
25
26
27
28
29
30
private :
// A t r i b u t o s p r i v a d o s
q l o n g l o n g m_codigo ;
QString m_nome ;
QString m_descricao ;
QDateTime m_ultimaAlteracao ;
q u i n t 1 6 m_versao ;
QByteArray m_arquivo ;
};
48
49
Nome: Consiste de um nome para identificar o arquivo armazenado. armazenado internamente no atributo privado m_nome e acessvel atravs dos mtodos nome
(leitura) e setNome (escrita);
Descrio: Consiste de um campo de texto com uma descrio do arquivo armazenado.
armazenada internamente no atributo privado m_descricao e acessvel atravs
dos mtodos descricao (leitura) e setDescricao (escrita);
ltima alterao: Armazena a data e hora em que foi efetuada a ltima alterao no arquivo armazenado. armazenado internamente no atributo privado m_ultimaAlteracao
e acessvel atravs dos mtodos ultimaAlteracao (leitura) e setUltimaAlteracao
(escrita);
Verso: Armazena o nmero da verso do arquivo armazenado. armazenado internamente pelo atributo m_versao e acessvel atravs dos mtodos versao (leitura)
e setVersao (escrita);
Arquivo: Armazena a sequncia de bytes em formato puro, que compe o arquivo armazenado. armazenado internamente no atributo privado m_arquivo e acessvel
atravs dos mtodos arquivo (leitura) e setArquivo (escrita).
Esta classe foi mapeada para o banco de dados utilizando os mecanismos presentes
nas trs bibliotecas ORM utilizadas no teste. O mapeamento foi configurado de forma que
a classe mapeada para uma tabela com nome t_documentos, o atributo m_codigo
mapeado para a coluna c_codigo, o atributo m_nome para a coluna c_nome,
o atributo m_descricao para a coluna c_descricao, o atributo m_ultimaAlteracao
para a coluna c_ultimaalteracao, o atributo m_versao para a coluna c_versao e o
atributo m_arquivo para a coluna c_arquivo.
Nas sees seguintes so apresentados os mecanismos utilizados para configurao do
mapeamento com cada uma das bibliotecas testadas.
5.2.1.1
O mapeamento com a biblioteca ORM4Qt foi configurado atravs da adio de uma srie
de macros no final do bloco de definio da classe. O trecho de cdigo 21 demonstra as
macros utilizadas para configurar o mapeamento.
Nas linhas 2 e 11 temos as macros que definem o incio e final da regio de configurao
do mapeamento, respectivamente. Na linha 3 temos a macro CLASS que utilizada
1
2
3
4
5
6
7
8
9
10
11
50
//Orm4Qt a n n o t a t i o n s
ORM4QT_BEGIN
CLASS( name="Documento" , autocolumn=" c o d i g o " , t a b l e=" t_documento " )
PROPERTY( m_codigo , name=" c o d i g o " , column=" c_codigo " , key=t r u e )
PROPERTY(m_nome, name="nome" , column="c_nome" )
PROPERTY( m_descricao , name=" d e s c r i c a o " , column=" c _ d e s c r i c a o " )
PROPERTY( m_ultimaAlteracao , name=" u l t i m a A l t e r a c a o " ,
column=" c _ u l t i m a a l t e r a c a o " )
PROPERTY( m_versao , name=" v e r s a o " , column=" c_versao " )
PROPERTY( m_arquivo , name=" a r q u i v o " , column=" c_arquivo " )
ORM4QT_END
Para realizar o mapeamento com a biblioteca ODB foi necessrio incluir uma srie de
diretivas de pr-processamento no arquivo de definio da classe. Para o desenvolvimento
do aplicativo de testes tambm foi necessria a definio de duas estruturas, que so
51
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// E s t r u t u r a usada para c o n t a r a q u a n t i d a d e de r e g i s t r o s
#pragma db view o b j e c t ( Documento )
s t r u c t DocumentoInfo
{
#pragma db column ( " count ( " + Documento : : m_codigo + " ) " )
std : : size_t quantidade ;
};
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// E s t r u t u r a u t i l i z a d a para l i m i t a r a s p r o p r i e d a d e s p e s q u i s a d a s
#pragma db view o b j e c t ( Documento )
s t r u c t DocumentoView
{
#pragma db column ( Documento : : m_codigo )
qlonglong codigo ;
#pragma db column ( Documento : : m_nome)
QString nome ;
#pragma db column ( Documento : : m_descricao )
QString d e s c r i c a o ;
#pragma db column ( Documento : : m_ultimaAlteracao )
QDateTime u l t i m a A l t e r a c a o ;
#pragma db column ( Documento : : m_versao )
quint16 versao ;
};
52
Para configurar o mapeamento com a biblioteca QxOrm foi necessrio incluir uma macro
no bloco de definio da classe para ativar o mecanismo de classes friend da linguagem
C++, permitindo biblioteca o acesso aos atributos privados. Foi necessrio tambm
incluir uma srie de macros extras no arquivo de definio da classe e implementar uma
funo de registro de metadados. No trecho de cdigo 23 possvel observar o cdigo
utilizado para o mapeamento.
Na linha 2 mostrada a macro que foi inserida dentro do bloco de declarao da
classe para ativao do mecanismo de classes friend. Na linha 5 utilizada uma macro
para informar para a biblioteca o tipo de dado do campo de chave primria utilizado na
classe. Nas linhas 6 at 12 so utilizadas macros para informar para a biblioteca que a
classe Documento deve ser mapeada para o banco de dados. Note que nestas linhas foi
necessrio utilizar diretivas de pr-processamento para informar macros diferentes para
os sistemas Ubuntu e Windows.
Nas linhas 15 at 28 demonstrada a implementao do mtodo de registro de metadados para classes mapeadas por esta biblioteca. Dentro desta funo, na linha 19
definida a tabela equivalente a classe, e nas linhas 21 at 26 so definidas as equivalncias
entre atributos e colunas.
Das trs bibliotecas utilizadas, esta a que possui o sistema de configurao mais
complexo. Como o aplicativo foi desenvolvido para ser utilizado nas plataformas Ubuntu
e Windows, foi necessrio utilizar, em certos pontos, macros de configurao diferentes
para os dois sistemas, como pode ser observado.
1
2
53
3
4
5
6
7
8
9
10
11
12
// Macros e x t r a s d e f i n i d a s no a r q u i v o de d e f i n i o da c l a s s e
QX_REGISTER_PRIMARY_KEY( E n t i d a d e s : : Documento , q l o n g l o n g )
#i f
d e f i n e d (Q_OS_WIN32)
QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL( E n t i d a d e s : : Documento , \
qx : : t r a i t : : no_base_class_defined , 0 , Documento )
#e l i f
d e f i n e d (Q_OS_LINUX)
QX_REGISTER_COMPLEX_CLASS_NAME_HPP( E n t i d a d e s : : Documento , \
qx : : t r a i t : : no_base_class_defined , 0 , Documento )
#e n d i f
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
5.2.2
54
A Classe IRepository
// Retorna um t e x t o com a d e s c r i o do l t i m o e r r o o c o r r i d o .
QString l a s t E r r o r ( ) c o n s t ;
// C r i a um novo r e g i s t r o de um o b j e t o no banco de dados
v i r t u a l b o o l c r e a t e O b j e c t (T &o b j e c t ) ;
// A t u a l i z a o r e g i s t r o de um o b j e t o no banco de dados
v i r t u a l b o o l updateObject (T &o b j e c t ) ;
// D e l e t a o r e g i s t r o de um o b j e t o no banco de dados
v i r t u a l b o o l d e l e t e O b j e c t (T &o b j e c t ) ;
// S e l e c i o n a uma l i s t a de o b j e t o s do banco de dados
// que obedecem o s f i l t r o s i n f o r m a d o s .
v i r t u a l b o o l s e l e c t O b j e c t s ( QList<T> &l i s t , QMap<QString , QVariant>
filters );
// Retorna a q u a n t i d a d e de r e g i s t r o s de o b j e t o s no banco de dados
// que obedecem o s f i l t r o s i n f o r m a d o s .
v i r t u a l b o o l c o u n t O b j e c t s ( i n t &count , QMap<QString , QVariant> f i l t e r s ) ;
// P e s q u i s a um r e g i s t r o e s p e c f i c o a p a r t i r do i d informado
v i r t u a l b o o l g e t O b j e c t ( c o n s t QVariant &id , T &o b j e c t ) ;
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
};
55
Captulo 6
Concluso
O objetivo principal deste trabalho foi mostrar que a partir da utilizao dos novos recursos, sobretudo os de programao funcional, propostos pelas novas especificaes da
linguagem C++, possvel construir uma biblioteca de mapeamento objeto relacional
com uma interface de configurao mais amigvel para o desenvolvedor. Para provar
esta teoria foi desenvolvida a biblioteca ORM4Qt, uma biblioteca ORM voltada para
utilizao integrada ao framework Qt.
A biblioteca desenvolvida mostrou-se com um nvel de facilidade de uso mais alto,
sobretudo na parte de configurao do mapeamento, quando comparada com duas existentes no mercado, a ODB e a QxOrm. Um dos motivos para isso acontecer consiste
no mecanismo de reflexo desenvolvido especificamente para a biblioteca, que permite a
configurao do mapeamento e insero de metadados com uma interface bem parecida
com o mecanismo de anotaes presente nas linguagens JAVA e C#.
Apesar de apresentar uma interface de configurao mais simples, a biblioteca desenvolvida no pde ser comparada diretamente com outras em quesitos como o suporte
a mapeamento de mecanismos mais avanados da orientao a objetos (como herana e
polimorfismo, por exemplo). Isso se deve ao fato de o suporte a tais mecanismos no ter
sido desenvolvido por no fazer parte do escopo principal do trabalho.
Tambm no foi comparado o desempenho das bibliotecas em relao ao tempo de
resposta e utilizao de memria, devido tambm ao fato da diferena da quantidade de
mecanismos implementados entre as bibliotecas existentes e a desenvolvida. Porm, ao
utilizar o aplicativo Minhas Apostilas, que foi desenvolvido para fins de testes entre as
trs bibliotecas, a diferena de tempo de resposta imperceptvel ao usurio.
A biblioteca ORM4Qt apresenta potencial para se tornar uma biblioteca ORM to
6 Concluso
57
completa quanto as utilizadas para testes de comparao. Para que isso seja possvel
preciso ampliar o mecanismo de reflexo de forma a detectar a utilizao de herana nas
classes mapeadas e reconstruir toda a camada de armazenamento para suportar operaes
no banco de dados que envolvam mais de uma tabela, ao necessria para suportar o
mapeamento de composio e associao. Estas melhorias podem ser implementadas em
trabalhos futuros.
Outra sugesto de trabalho futuro consiste na utilizao do mecanismo de reflexo
criado, para implementao de mecanismos de serializao de objetos para arquivos XML
e JSON.
Referncias Bibliogrficas
[Barnes, 2007] Barnes, J. M. (2007). Object-relational mapping as a persistence mechanism for object-oriented applications.
[Bauer and King, 2005] Bauer, C. and King, G. (2005). Hibernate in Action, volume 1.
Manning Publications Co.
[Blanchette and Summerfield, 2006] Blanchette, J. and Summerfield, M. (2006). C++
GUI programming with Qt 4. OReilly Japan.
[Brokken and Kubat, 2014] Brokken, F. B. and Kubat, K. (2014). C++ annotations.
Citeseer.
[Bueno, 2002] Bueno, A. (2002). Apostila de programao orientada a objeto em c++.
[Clugston, 2004] Clugston, D. (2004). Member function pointers and the fastest possible
c++ delegates. Online Article.
[Gregoire, 2014] Gregoire, M. (2014). Professional C++, volume 3. WROX.
[Lhotka, 2009] Lhotka, R. (2009). Expert C# 2008 Business Objects, volume 1. Apress.
[Marty, 2014] Marty, L. (2014). Qxorm - c++ object relational mapping library. http:
//www.qxorm.com/doxygen/html/index.html.
[Nierstrasz, 1989] Nierstrasz, O. (1989). A survey of object-oriented concepts.
[PostgreSQL, 2014] PostgreSQL, T. G. D. G. (2014). PostgreSQL 9.3.4 Documentation.
[Synthesis, 2013] Synthesis, C. (2013). C++ Object Persistence with ODB.
[Thelin, 2007] Thelin, J. (2007). Foundations of Qt development, volume 7. Springer.
[Zhang, 2004] Zhang, X. (2004). A framework for object-relational mapping with an example in C++. PhD thesis, Concordia University.