Diretrizes:
|
|
|
O modelo de dados é um subconjunto do modelo de implementação que descreve a representação lógica e física de dados persistentes no sistema. |
A orientação a objetos e os bancos de dados relacionais não são totalmente compatíveis. Eles representam duas visões distintas do mundo: em um RDBMS, tudo que você vê são dados. Em um sistema orientado a objetos, tudo que você vê são comportamentos. Não que uma perspectiva seja melhor do que a outra: o modelo orientado a objetos tende a funcionar melhor em sistemas com comportamento complexo e específico de estados, nos quais os dados são secundários. Esse modelo também é eficaz em sistemas cujos dados são acessados, através de navegação, em uma hierarquia natural (por exemplo, listas de materiais). O modelo RDBMS é adequado para relatar aplicativos e sistemas cujos relacionamentos sejam dinâmicos ou ad-hoc.
A verdade é que um volume grande de informações é armazenado em bancos de dados relacionais e, se os aplicativos orientados a objetos quiserem ter acesso a esses dados, precisam ser capazes de ler e gravar em um RDBMS. Além disso, é comum os sistemas orientados a objetos precisarem compartilhar dados com sistemas que não são orientados a objetos. É natural, portanto, usar um RDBMS como mecanismo de compartilhamento.
Embora o design orientado a objetos e o design relacional tenham algumas características em comum (os atributos de objeto são teoricamente semelhantes às colunas de entidades), há diferenças fundamentais que fazem da integração completa um verdadeiro desafio. A diferença básica é que os modelos de dados expõem os dados (através de valores de coluna), enquanto os modelos de objeto ocultam os dados (encapsulados atrás de suas interfaces públicas).
O modelo relacional é composto de entidades e relacionamentos. Uma entidade pode ser uma tabela física ou uma projeção lógica de diversas tabelas, também conhecida como visão. A figura abaixo mostra as tabelas LINEITEM e PRODUCT e os vários relacionamentos existentes entre elas. Um modelo relacional tem os seguintes elementos:

Um Modelo Relacional
As entidades têm colunas. Cada coluna é identificada por um nome e um tipo. Na figura acima, a entidade LINEITEM contém as colunas LineItem_Id (a chave primária), Description, Price, Quantity, Product_Id e Order_Id (as duas últimas são chaves estrangeiras que vinculam a entidade LINEITEM às entidades ORDER e PRODUCT).
As entidades têm registros ou linhas. Cada linha representa um conjunto exclusivo de informações que geralmente representam os dados persistentes de um objeto.
Cada entidade tem uma ou mais chaves primárias. As chaves primárias identificam cada registro com exclusividade. Por exemplo, Id é a chave primária da tabela LINEITEM.
O suporte a relacionamentos é um recurso específico do fornecedor. O exemplo mostra o modelo lógico e o relacionamento entre as tabelas PRODUCT e LINEITEM. No modelo físico, os relacionamentos geralmente são implementados usando referências de chave estrangeira e chave primária. Se uma entidade estiver relacionada a outra, ela conterá colunas que serão chaves estrangeiras. Colunas de chave estrangeira contêm dados que podem relacionar determinados registros na entidade à entidade relacionada.
Há multiplicidade (também chamada de cardinalidade) nos relacionamentos. As cardinalidades comuns são de um para um (1:1), de um para muitos (1:m), de muitos para um (m:1) e de muitos para muitos (m:n). No exemplo, LINEITEM tem um relacionamento 1:1 com PRODUCT, e PRODUCT tem um relacionamento 0:m com LINEITEM.
Um modelo de objetos contém, entre outras coisas, classes (consulte [UML99] para obter uma definição completa sobre um modelo de objeto). As classes definem a estrutura e o comportamento de um conjunto de objetos, às vezes denominadas instâncias de objetos. A estrutura é representada como atributos (valores de dados) e associações (relacionamentos entre classes). A figura a seguir mostra um diagrama simples de classes que possui apenas atributos (dados) das classes.

Um Modelo de Objetos (Diagrama de Classes)
Um Pedido tem um número (o Número do Pedido) e uma associação com 1 ou mais (1..*) Itens de Linha. Cada Item de Linha tem uma quantidade (a quantidade pedida).
O modelo de objetos suporta heranças. Uma classe pode herdar dados e comportamentos de outra classe. Por exemplo, os produtos de SoftwareProduct e HardwareProduct herdam atributos e métodos da classe Produto).
A maioria dos aplicativos de negócios utiliza a tecnologia relacional como um armazenamento físico de dados. O desafio dos desenvolvedores de aplicativos orientados a objetos é separar e encapsular o banco de dados relacional para que as mudanças efetuadas no modelo de dados não desestruturem o modelo de objetos e vice-versa. Várias soluções permitem que os aplicativos acessem diretamente os dados relacionais. O desafio está em conseguir uma integração completa entre o modelo de objetos e o modelo de dados.
As APIs de bancos de dados têm padrões conhecidos (por exemplo, a API de Conectividade Aberta de Banco de Dados da Microsoft - ODBC) e são proprietárias (vinculações nativas para bancos de dados específicos). As APIs oferecem serviços de acesso a linguagem de manipulação de dados (DML) que possibilitam o acesso de aplicativos a dados relacionais brutos. Em aplicativos orientados a objetos, os dados devem ser submetidos a uma conversão objeto-relacional antes de serem usados pelo aplicativo. Esse procedimento requer um volume considerável de código do aplicativo para converter resultados brutos da API do banco de dados em objetos do aplicativo. A finalidade do framework objeto-relacional é encapsular genericamente o armazenamento físico de dados e fornecer serviços adequados de conversão de objetos.

A Finalidade do Framework de Persistência
Os desenvolvedores de aplicativos gastam mais de 30% de seu tempo implementando o acesso a bancos de dados relacionais em aplicativos orientados a objetos. Se a interface objeto-relacional não for implementada corretamente, o investimento será perdido. A implementação de um framework objeto-relacional captura esse investimento. Esse tipo de framework poderá ser reutilizado em aplicativos subseqüentes, o que reduz o custo de implementação para menos de 10% do custo total da implementação. O custo mais importante a ser considerado durante a implementação de qualquer sistema é o de manutenção. Mais de 60% por cento do custo total de um sistema durante seu ciclo de vida útil pode ser atribuído à manutenção. Um sistema objeto-relacional mal implementado é um pesadelo técnico e financeiro para a manutenção.
Os aplicativos objeto-relacional têm apresentado padrões comuns. Os profissionais de TI, que se deparam repetidamente com lacunas, estão começando a entender e a reconhecer certas estruturas e comportamentos dos aplicativos objeto-relacional bem-sucedidos. Tais estruturas e comportamentos foram formalizados pelas especificações de serviços CORBA de alto nível, que também se aplicam satisfatoriamente a sistemas baseados em COM/DCOM.
As especificações de serviços CORBA aplicáveis e úteis para o mapeamento objeto-relacional são:
As próximas seções usarão essas categorias para abordar os serviços objeto-relacional comuns. Aconselhamos o leitor a consultar as especificações CORBA adequadas para obter mais detalhes.
Persistência é um termo usado para descrever como os objetos utilizam um meio de armazenamento secundário para manter seu estado entre sessões distintas. A persistência permite ao usuário salvar objetos em uma sessão e acessá-los em uma sessão posterior. Quando eles são acessados subseqüentemente, seu estado (por exemplo, atributos) permanecerá igual ao da sessão anterior. Em sistemas multiusuários, talvez não seja esse o caso, já que vários usuários podem acessar e modificar os mesmos objetos. A persistência está inter-relacionada a outros serviços abordados nesta seção. Relacionamentos, simultaneidade e outros aspectos devem ser intencionalmente considerados (e estar consistentes com a especificação CORBA para a decomposição dos serviços).
Exemplos de serviços específicos oferecidos pela persistência:
O armazenamento de objetos persistentes é pouco útil se não houver um mecanismo para procurar e recuperar objetos específicos. Os recursos de consulta permitem que os aplicativos verifiquem e recuperem objetos com base em vários critérios. As operações básicas de consulta obtidas com um framework de mapeamento objeto-relacional são operações de localização (find) e localização exclusiva (find unique). A operação de localização exclusiva recupera objetos específicos, enquanto a operação de localização retorna um conjunto de objetos com base em um critério de consulta.
Os recursos de consulta de armazenamentos de dados variam significativamente. Os armazenamentos de dados baseados em arquivos simples podem implementar operações rígidas de consulta desenvolvidas internamente, enquanto os sistemas relacionais oferecem uma linguagem de manipulação de dados flexível. Os frameworks de mapeamento objeto-relacional expandem o modelo de consulta relacional para que sejam centralizados nos objetos, e não nos dados. Os mecanismos de acesso também são implementados para aproveitar a flexibilidade de consultas relacionais e as extensões específicas do fornecedor (por exemplo, os procedimentos armazenados).
Observe que há alguma possibilidade de conflito entre o paradigma do objeto e os mecanismos de consulta que se baseiam no banco de dados. Os mecanismos de consulta do banco de dados são orientados por valores de atributos (colunas) em uma tabela. Nos objetos correspondentes, o princípio de encapsulamento impede a visualização dos valores de atributos. Eles são encapsulados por operações da classe. O motivo do encapsulamento é facilitar a realização de mudanças nos aplicativos. É possível alterar a estrutura interna de uma classe sem se preocupar com classes dependentes, desde que as operações publicamente visíveis da classe não mudem. Um mecanismo de consulta baseado no banco de dados depende da representação interna de uma classe, o que efetivamente prejudica o encapsulamento. O desafio do framework é evitar que as consultas alterem os aplicativos mais frágeis.
O suporte transacional permite que o desenvolvedor de aplicativos defina uma unidade atômica de trabalho. Na terminologia de bancos de dados, isso significa que o sistema deve ser capaz de aplicar um conjunto de mudanças ao banco de dados ou assegurar que nenhuma mudança seja aplicada. Se todas as operações que ocorrem em uma transação não forem executadas com sucesso, a transação falha como um todo. Os frameworks objeto-relacional devem oferecer às transações, no mínimo, um recurso de confirmação e rollback como o dos bancos de dados relacionais. O design de frameworks objeto-relacional em um ambiente multiusuário pode apresentar vários desafios; por isso, ele deve ser encarado com cuidado.
Além dos recursos fornecidos pelo framework de persistência, o aplicativo deve saber como tratar os erros. Quando uma transação falha ou é abortada, o sistema deve ser capaz de restaurar o estado de estabilidade anterior à falha. Geralmente, isso é obtido por meio da leitura de informações sobre o estado anterior obtidas do banco de dados. Dessa forma, ocorre uma perfeita interação entre o framework de persistência e o framework para o tratamento de erros.
Os sistemas multiusuários orientados a objetos devem controlar o acesso simultâneo a objetos. Quando um objeto é acessado simultaneamente por vários usuários, o sistema deve ter um mecanismo para garantir que as modificações efetuadas no objeto no armazenamento persistente ocorram de maneira previsível e controlada. Os frameworks objeto-relacional podem implementar controles de simultaneidade pessimistas e/ou otimistas.
Todos os aplicativos que utilizam dados compartilhados devem usar a mesma estratégia de simultaneidade. Não é possível combinar o controle de simultaneidade otimista e o pessimista nos mesmos dados compartilhados, pois eles podem ser danificados. Uma estratégia de simultaneidade consistente é melhor aplicada com um framework de persistência.
Os objetos mantêm relacionamentos com outros objetos. Um objeto Pedido tem muitos objetos Item de Linha. Um objeto Livro tem muitos objetos Capítulo. Um objeto Funcionário pertence a um objeto Empresa. Nos sistemas relacionais, os relacionamentos entre as entidades são implementados com referências de chave estrangeira e chave primária. Em sistemas orientados a objetos, os relacionamentos costumam ser explicitamente implementados por meio de atributos. Se um objeto Pedido tiver Itens de Linha, então Pedido conterá um atributo denominado Itens de Linha. O atributo Itens de Linha de Pedido conterá muitos objetos Item de Linha.
Os aspectos de relacionamento de um framework objeto-relacional são interdependentes dos serviços de persistência, transação e consulta. Quando um objeto é armazenado, recuperado, transacionado ou consultado, os objetos relacionados devem receber especial atenção:
Embora seja teoricamente vantajoso considerar os serviços objeto-relacional comuns separadamente, as implementações do framework serão co-dependentes. Os serviços devem ser implementados com consistência não apenas nas organizações individuais, mas em todos os aplicativos que compartilham os mesmos dados. O framework é o único meio econômico de obter isso.
As classes persistentes no Modelo de Design representam as informações que o sistema deve armazenar. Teoricamente, essas classes podem assemelhar-se a um design relacional. Por exemplo, as classes no modelo de design podem ser refletidas, de certa forma, como entidades no esquema relacional. Entretanto, à medida que passamos da fase de elaboração para a de construção, as metas do Modelo de Design e do Modelo de Dados Relacional divergem. Essa divergência ocorre porque o objetivo do desenvolvimento do banco de dados relacional é normalizar os dados, enquanto a meta do Modelo de Design é encapsular comportamentos cada vez mais complexos. A divergência entre essas duas perspectivas - dados e comportamento - gera a necessidade de mapeamento entre elementos relacionados nos dois modelos.
Em um banco de dados relacional escrito na terceira forma normal, cada linha das tabelas - cada "tupla" - é considerada um objeto. Uma coluna em uma tabela equivale a um atributo persistente de uma classe. Lembre-se de que uma classe persistente pode ter atributos transientes. No caso de não haver associações com outras classes, o mapeamento entre os dois mundos é um procedimento simples. O tipo de dado do atributo corresponde a um dos tipos de dados permitidos para colunas.
Exemplo
A classe Cliente:

quando modelada no RDBMS é convertida em uma tabela denominada Cliente, com as colunas Nome, Endereço e Customer_ID.
Uma instância dessa tabela pode ser visualizada como:

Para cada atributo persistente, informações adicionais são necessárias para modelar corretamente o objeto persistente em um modelo de dados relacional:
As linhas das tabelas precisam ter uma identidade exclusiva. Elas são identificadas com exclusividade pelos valores de suas chaves primárias. A chave primária será usada como referência a uma tupla nessa tabela originada de outras tabelas. Ela identificará com exclusividade a linha ou o objeto das pesquisas. Conseqüentemente, nunca deve ser alterada. Os nomes em texto sem formatação não são adequados. As pessoas alteram seus nomes e nomes não são exclusivos. Como as comparações numéricas consomem menos recursos do que as comparações de seqüências de caracteres, as chaves primárias devem ser numéricas e, preferencialmente, atribuídas pelo sistema, para que não sejam alteradas.
Geralmente, as chaves primárias são indexadas por questões de desempenho. Entretanto, essa é uma decisão de implementação e não depende do mapeamento do objeto para a tabela.
As associações entre dois objetos persistentes são realizadas como chaves estrangeiras para os objetos associados. Uma chave estrangeira é uma coluna em uma tabela que contém o valor da chave primária do objeto associado.
Exemplo
Suponha que exista a seguinte associação entre Pedido e Cliente:

Quando essas informações forem mapeadas para as tabelas relacionais, teremos uma tabela Pedido e uma tabela Cliente. A tabela Pedido terá colunas para os atributos listados - e mais uma coluna adicional, Customer_ID - com as referências de chave estrangeira para a chave primária das linhas associadas na tabela Cliente. Para determinado Pedido, a coluna Customer_ID conterá o identificador do Cliente a quem o Pedido está associado. As chaves estrangeiras permitem que o RDBMS agrupe as informações relacionadas.
Observação: O atributo customerID da classe Cliente é uma Seqüência de Caracteres. Para obter um bom desempenho, é melhor convertê-lo em um Número no esquema do banco de dados (consultas e junções funcionam com maior rapidez com números do que com seqüências de caracteres, já que as comparações numéricas são mais rápidas do que seqüenciais).
A agregação também é modelada usando relacionamentos de chaves estrangeiras.
Exemplo
Suponha que exista a seguinte associação entre Pedido e Item de Linha:

Quando essas informações forem mapeadas para as tabelas relacionais, teremos uma tabela Pedido e uma tabela Line_Item. A tabela Line_Item terá colunas para os atributos listados, mais uma coluna adicional, Order_ID, que contém as referências de chave estrangeira para as linhas associadas da tabela Pedido. Para determinado Item de Linha, a coluna Order_ID conterá o Order_ID do Pedido ao qual o Item de Linha está associado. As chaves estrangeiras permitem que o RDBMS agrupe as informações relacionadas.
Além disso, para oferecer integridade referencial ao modelo de dados, é recomendável implementar uma restrição de exclusão em cascata, para que, sempre que o Pedido for excluído, todos os Itens de Linha também o sejam.
Lembre-se: no modelo de objeto, um cliente conhece suas ordens de compra. No modelo de dados relacional, uma ordem de compra tem informações sobre seus clientes. Essa é uma demonstração de como os relacionamentos são representados em um modelo de dados relacional.
O modelo de dados relacional padrão não suporta modelar herança de uma forma direta. Há várias estratégias que podem ser usadas para modelar herança. Elas podem ser resumidas da seguinte maneira:
Uma técnica padrão na modelagem relacional é usar uma entidade de interseção para representar associações de muitos-para-muitos. A mesma abordagem deve ser usada aqui: uma tabela de interseção deve ser usada para representar a associação.
Exemplo
Se Fornecedores podem oferecer muitos Produtos e um Produto pode ser oferecido por vários Fornecedores, a solução é criar uma tabela Fornecedor/Produto. Essa tabela deve conter somente as chaves primárias das tabelas Fornecedor e Produto e servirá para vincular os Fornecedores a seus Produtos. Não há uma tabela equivalente a essa no modelo de objetos. Ela é usada apenas para representar as associações no modelo de dados relacional.
No modelo de objetos, a integridade referencial não constitui um problema. Os objetos fazem referências um ao outro diretamente. No modelo de dados relacional, as linhas fazem referência a outras linhas por meio dos valores de suas chaves primárias. As regras de integridade referencial são necessárias para manter a validade das referências de chave estrangeira. Geralmente, essas regras são implementadas como restrições de integridade ou, em alguns casos, como triggers. Os manuais de referência do RDBMS podem oferecer mais informações sobre a técnica de implementação apropriada.
A meta da elaboração é eliminar riscos técnicos e produzir uma arquitetura estável (com boa baseline). Em muitos sistemas de negócios, o mau desempenho resultante de um modelo de dados projetado incorretamente é uma das principais preocupações em termos de arquitetura. Como conseqüência, a modelagem de dados e o desenvolvimento de um protótipo de arquitetura que permita que o desempenho do banco de dados seja avaliado é essencial para a obtenção de uma arquitetura estável.
As principais estruturas do banco de dados (tabelas, índices, colunas de chave primária e chave estrangeira) devem ser usadas para suportar cenários significativos do ponto de vista da arquitetura. Além disso, grandes volumes de dados devem ser carregados nos bancos de dados para suportar testes de desempenho da arquitetura. Com base nos resultados do teste de desempenho, talvez o modelo de dados precise ser otimizado, incluindo, entre outros, desnormalização, otimização de atributos de armazenamento físico, distribuição ou indexação.
Na fase de construção, colunas adicionais podem ser incluídas nas tabelas, visões que suportem requisitos de consulta e relatório podem ser criadas e índices podem ser elaborados para otimizar o desempenho. Não devem ocorrer grandes reestruturações da tabela, pois isso demonstra que a arquitetura não está estabilizada e que o início da fase de construção foi prematuro.
|
Rational Unified Process
|