Header Ads

O que é uma "incompatibilidade de impedância" na programação?

Shutterstock / oatawa

Uma incompatibilidade de impedância de programação ocorre quando os dados precisam ser transformados em um paradigma de arquitetura diferente. O exemplo mais proeminente envolve bases de código orientadas a objetos e bancos de dados relacionais.

Uma incompatibilidade de impedância surge quando os dados são buscados ou inseridos em um banco de dados. As propriedades de objetos ou classes dentro da base de código precisam ser mapeadas para seus campos de tabela de banco de dados correspondentes.

Mapeamento e relacionamentos

Suas aulas não serão necessariamente mapeadas diretamente para tabelas individuais do banco de dados. A construção de um objeto pode exigir que dados de várias tabelas sejam usados ​​de forma agregada.

Você também precisará lidar com as relações entre os seus dados. Os bancos de dados relacionais tornam isso simples, permitindo que você faça referência a outros registros. Você pode usar um JOIN para acessar todos os dados encapsulados pelo relacionamento.

CREATETABLE productTypes & # 40; ProductTypeUuid VARCHAR & # 40; 32 & # 41; PRIMARYKEY, ProductTypeName VARCHAR & # 40; 255 & # 41; NOTNULLUNIQUE & # 41 ;;   Produtos CRIÁVEIS & # 40; ProductUuid VARCHAR & # 40; 32 & # 41; PRIMARYKEY, ProductName VARCHAR & # 40; 255 & # 41; NOTNULLUNIQUE, ProductType VARCHAR & # 40; 32 & # 41; NOTNULL, FOREIGNKEY & # 40; ProductType & # 41; REFERÊNCIAS productTypes & # 40; ProductType ;uid CASCATA ONDELETE & # 41 ;;

Usando SQL simples, você poderia obter as propriedades combinadas de um Produto e seu ProductType com esta consulta simples:

SELECIONE * DOS produtos INNERJOIN productTypes ON ProductTypeUuid = ProductType;

Em seguida, as propriedades do Produto e seu ProductType são acessadas a partir da mesma estrutura plana:

echo $ record & # 91; " ProductName " & # 93 ;; echo $ record & # 91; " ProductTypeName " & # 93 ;;

Esta matriz plana rapidamente se torna limitante em aplicativos complexos. Os desenvolvedores modelam naturalmente as entidades Product e ProductType como classes separadas. A classe Product pode então conter uma instância de um ProductType. Veja como fica:

classe final ProductType & # 123;   publicfunction __construct & # 40; public string $ Uuid, public string $ Name & # 41; & # 123; & # 125;   & # 125;   classe final Produto & # 123;   publicfunction __construct & # 40; public string $ Uuid, public string $ Name, public ProductType $ ProductType & # 41; & # 123; & # 125;   & # 125;

Agora há uma incompatibilidade de impedância significativa no código. É necessária alguma forma de mapeamento especializado antes que os registros da consulta ao banco de dados possam ser representados como instâncias do Produto.

Outras complicações surgem quando você deseja acessar todos os produtos de um tipo específico. Veja como você pode fazer isso no código:

classe final ProductType & # 123;   publicfunction __construct & # 40; public string $ Uuid, public string $ Name, ProductCollection $ Products & # 41; & # 123; & # 125;   & # 125;

Agora, o ProductType contém um ProductCollection, que, em última análise, conteria uma matriz de instâncias de Product. Isso cria uma referência relacional bidirecional – ProductType contém todos os seus produtos e cada Produto contém seu tipo de produto.

Esta forma de modelagem não existe dentro do paradigma relacional. Cada forma de conexão é representada com um único registro de link relacional. O uso de referências bidirecionais simplifica o acesso do desenvolvedor às propriedades do objeto. No entanto, requer um mapeamento mais complexo quando transferido de e para o banco de dados. Isso ocorre porque o SQL não entende nativamente a semântica do modelo.

Considerando a hierarquia

O modelo explicado acima cria uma hierarquia na base de código: o produto fica abaixo do ProductType. Isso parece lógico e corresponde às nossas expectativas do mundo real.

Os bancos de dados relacionais não respeitam hierarquias. Como todos os relacionamentos são equivalentes, os bancos de dados relacionais têm uma estrutura inerentemente “ plana ” estrutura. Vimos isso antes, ao buscar dados com um JOIN.

A falta de hierarquia no SQL significa que todas as tabelas possuem uma prioridade equivalente entre si. Um efeito disso é que você pode acessar facilmente as propriedades dos registros aninhados nas profundezas da hierarquia de objetos lógicos. Além disso, há um risco menor de dependências cíclicas.

O exemplo acima mostra que Product e ProductType podem acabar se referindo um ao outro no código; a natureza simples dos bancos de dados relacionais evitaria que esse exemplo específico ocorresse. Os ciclos ainda podem surgir no SQL simples, mas é menos provável que você os encontre do que ao modelar com código orientado a objetos.

A programação orientada a objetos depende da composição de objetos simples em outros mais complexos. Os modelos relacionais não têm essa noção de composição ou de “ simples ” e “ complexo ” – qualquer registro pode fazer referência a qualquer outro.

Herança

Outra função exclusiva da OOP é a herança. É comum uma classe estender outra, adicionando comportamentos adicionais. Os bancos de dados relacionais não conseguem replicar isso. É impossível para uma tabela “ estender ” outra mesa.

Uma base de código que usa herança encontrará dificuldades quando os objetos filhos forem persistidos ou hidratados por meio de um banco de dados relacional. No banco de dados, você geralmente precisará de duas tabelas. Um armazena as propriedades do objeto base (que você está estendendo), com outro manipulando as propriedades do filho.

O código de mapeamento então itera todas as propriedades do objeto. As propriedades derivadas da classe estendida serão inseridas no primeiro código. Aqueles definidos diretamente na criança irão para a segunda tabela.

Um sistema semelhante é necessário ao mapear de volta para a base de código a partir do banco de dados. Um SQL JOIN pode ser usado para obter todos os registros correspondentes à classe base (estendida), com as propriedades filhas incluídas. Esses registros que continham as propriedades filhas seriam então mapeados para instâncias de classes filhas.

CREATETABLE parent & # 40; Id INTEGERPRIMARYKEY, A INTEGER & # 41 ;; CREATETABLE child & # 40; Id INTEGERPRIMARYKEY, B INTEGER, ParentId INTEGER & # 41 ;;

class Parent & # 123; publicfunction __construct & # 40; int $ A & # 41; & # 123; & # 125; & # 125;   classe final Child estende Parent & # 123; publicfunction __construct & # 40; int $ A, int $ B & # 41; & # 123; & # 125; & # 125;   // Obter registros // SELECT * FROM parent INNER JOIN child ON child. ParentId = parent. Id; $ objs = & # 91; & # 93 ;; foreach & # 40; $ recordsas $ record & # 41; & # 123; if & # 40; isset & # 40; $ record & # 91; " B " & # 93; & # 41; & # 41; & # 123; $ objs & # 91; & # 93; = novo filho & # 40; $ record & # 91; " A " & # 93 ;, $ record & # 91; " B " & # 93; & # 41 ;; & # 125; else $ objs & # 91; & # 93; = novo pai & # 40; $ registro & # 91; " A " & # 93; & # 41 ;; & # 125;

A introdução da herança requer o uso de uma lógica de mapeamento mais envolvida. A incapacidade dos bancos de dados relacionais de modelar os recursos de herança das linguagens orientadas a objetos introduz essa incompatibilidade de impedância.

Visibilidade e encapsulamento

Um princípio fundamental da programação orientada a objetos é a visibilidade e o encapsulamento. As propriedades são declaradas como públicas ou privadas. A representação interna de um objeto pode ser escondida atrás de uma interface que pré-formata os dados para o consumidor.

Os bancos de dados relacionais não têm esses controles. Não há como declarar um campo como privado, nem há uma necessidade óbvia de fazê-lo. Cada parte dos dados armazenados em um banco de dados tem sua própria finalidade; não deve haver redundância.

Isso não é necessariamente verdadeiro quando transposto para um paradigma orientado a objetos. Um objeto pode usar dois campos de banco de dados em conjunto para expor uma nova informação computada. Os valores dos dois campos individuais podem ser irrelevantes para o aplicativo e, conseqüentemente, ocultos da visualização.

Produtos CRIÁVEIS & # 40; Price INTEGER, TaxRate INTEGER & # 41 ;;

Produto final da classe & # 123;   função pública __construir & # 40; protegida int $ Preço, protegida int $ TaxRate & # 41; & # 123; & # 125;   publicfunction getTotalPrice & # 40; & # 41 ;: int & # 123; return & # 40; $ this- > Price * & # 40; $ this- > TaxRate / 100 & # 41; & # 41 ;; & # 125; & # 125;

O aplicativo se preocupa apenas com o preço total do produto, incluindo impostos. O preço unitário e a taxa de imposto são encapsulados pela classe de Produto. Os controles de visibilidade (protegidos) ocultam os valores. A interface pública consiste em um único método que usa os dois campos para calcular um novo valor.

De maneira mais geral, a programação orientada a objetos defende a programação para interfaces. O acesso direto às propriedades é desencorajado. O uso de métodos de classe que implementam uma interface permite que implementações alternativas sejam construídas no futuro.

Não há contrapartida direta para isso no mundo relacional. As visualizações do banco de dados fornecem uma maneira de combinar tabelas e campos abstratos em novos formulários. No entanto, você ainda está trabalhando diretamente com os valores dos campos.

Resumo

Incompatibilidades de impedância relacional de objeto ocorrem quando uma base de código orientada a objeto troca dados com um banco de dados relacional. Existem diferenças fundamentais na forma como os dados são modelados. Isso requer a introdução de uma camada de mapeamento que transpõe os dados entre os formatos.

O problema de incompatibilidade de impedância é um dos principais fatores de motivação na adoção de ORMs em linguagens orientadas a objetos. Eles permitem a hidratação automática de objetos complexos de base de código de fontes de dados relacionais. Sem uma camada de mapeamento de dados dedicada, apenas os aplicativos mais simples terão um caminho direto de e para um banco de dados relacional.

Nenhum comentário