Wat is een “Impedantie Mismatch” bij het programmeren?

0
237
Shutterstock/oatawa

Een mismatch in de programmeerimpedantie treedt op wanneer gegevens moeten worden getransformeerd naar een ander architectonisch paradigma. Het meest prominente voorbeeld betreft objectgeoriënteerde codebases en relationele databases.

Er ontstaat een impedantiemismatch wanneer gegevens worden opgehaald uit of ingevoegd in een database. De eigenschappen van objecten of klassen in de codebase moeten worden toegewezen aan de bijbehorende databasetabelvelden.

Mapping en relaties

Uw klassen worden niet noodzakelijkerwijs rechtstreeks toegewezen aan afzonderlijke databasetabellen. Voor de constructie van een object kunnen gegevens uit verschillende tabellen nodig zijn om samengevoegd te worden.

U moet ook omgaan met relaties tussen uw gegevens. Relationele databases maken dit eenvoudig doordat u naar andere records kunt verwijzen. U kunt een JOIN gebruiken om toegang te krijgen tot alle gegevens die door de relatie zijn ingekapseld.

MAAK TAFEL productTypes( ProductTypeUuid VARCHAR(32) PRIMAIRE SLEUTEL, ProducttypeNaam VARCHAR(255) NIET NUL UNIEK );   MAAK TAFEL producten( ProductUuid VARCHAR(32) PRIMAIRE SLEUTEL, productnaam VARCHAR(255) NIET NULL UNIEK, Producttype VARCHAR(32) NIET NULL, BUITENLANDSE SLEUTEL (ProductType) REFERENTIES productTypes(ProductTypeUuid) OP VERWIJDEREN CASCADE );

Met behulp van gewone SQL kunt u de gecombineerde eigenschappen van een product en zijn ProductType verkrijgen met deze eenvoudige query:

SELECT * FROM products INNER JOIN productTypes ON ProductTypeUuid = ProductType; Advertentie

De eigenschappen van het Product en het ProductType zijn dan toegankelijk vanuit dezelfde platte structuur:

echo $record["Productnaam"]; echo $record["ProductTypeName"];

Deze platte array wordt al snel beperkend in complexe toepassingen. Ontwikkelaars modelleren de entiteiten Product en ProductType natuurlijk als afzonderlijke klassen. De klasse Product kan dan een instantie van een ProductType bevatten. Zo ziet dat eruit:

eindklasse ProductType {   publieke functie __construct( openbare tekenreeks $Uuid, openbare tekenreeks $Naam) {}   }   eindklasse Product {   publieke functie __construct( openbare tekenreeks $Uuid, openbare tekenreeks $Naam, openbare ProductType $ProductType) {}   }

Er is nu een aanzienlijke mismatch in de impedantie in de code. Er is een of andere vorm van gespecialiseerde mapping vereist voordat records uit de databasequery kunnen worden weergegeven als Productinstanties.

Verdere complicaties doen zich voor wanneer u toegang wilt krijgen tot alle producten van een bepaald type. Hier is hoe je dat in code zou kunnen doen:

eindklasse ProductType {   publieke functie __construct( openbare tekenreeks $Uuid, openbare tekenreeks $Name, ProductCollection $Products) {}   }

Het ProductType bevat nu een ProductCollection, die uiteindelijk een reeks Productinstanties zou bevatten. Dit creëert een bidirectionele relationele referentie – ProductType bevat al zijn producten en elk Product bevat zijn producttype.

Deze vorm van modelleren bestaat niet binnen het relationele paradigma. Elke vorm van verbinding wordt weergegeven met een enkele relationele linkrecord. Het gebruik van bidirectionele verwijzingen vereenvoudigt de toegang van ontwikkelaars tot objecteigenschappen. Het vereist echter een complexere toewijzing bij overdracht van en naar de database. Dit komt omdat SQL de semantiek van het model niet standaard begrijpt.

Overwegen van hiërarchie

Advertentie

Het hierboven uitgelegde model creëert een hiërarchie in de codebase: Product staat onder ProductType. Dit klinkt logisch en komt overeen met onze verwachtingen van de echte wereld.

Relationele databases respecteren hiërarchieën niet. Aangezien alle relaties gelijkwaardig zijn, hebben relationele databases een inherent “plat” structuur. We zagen dit eerder bij het ophalen van gegevens met een JOIN.

Het ontbreken van hiërarchie in SQL betekent dat alle tabellen een gelijkwaardige prioriteit voor elkaar hebben. Een effect hiervan is dat u gemakkelijk toegang krijgt tot de eigenschappen van records die diep in uw logische objecthiërarchie zijn genest. Bovendien is er een lager risico op cyclische afhankelijkheden.

Het bovenstaande voorbeeld laat zien dat Product en ProductType in code naar elkaar kunnen verwijzen; de platte aard van relationele databases zou voorkomen dat dit specifieke voorbeeld zich voordoet. Cycli kunnen nog steeds opduiken in gewone SQL, maar je zult ze minder snel tegenkomen dan bij het modelleren met objectgeoriënteerde code.

Objectgeoriënteerd programmeren is gebaseerd op de samenstelling van eenvoudige objecten in complexere. Relationele modellen hebben niet zo'n notie van compositie of het “eenvoudige” en “complex” – elk record kan naar een ander verwijzen.

Overerving

Een andere exclusieve OOP-functie is overerving. Het is gebruikelijk dat een klas een andere uitbreidt en extra gedrag toevoegt. Relationele databases kunnen dit niet repliceren. Het is onmogelijk dat een tafel “uitbreidt” een andere tafel.

Advertentie

Een codebase die gebruikmaakt van overerving zal problemen ondervinden wanneer onderliggende objecten worden bewaard of gehydrateerd via een relationele database. Binnen de database heb je meestal twee tabellen nodig. De ene slaat de eigenschappen op van het basisobject (dat je uitbreidt), terwijl de andere de eigenschappen van het kind behandelt.

De toewijzingscode herhaalt vervolgens alle eigenschappen van het object. Eigenschappen die afkomstig zijn van de uitgebreide klasse zullen in de eerste code worden ingevoegd. Degenen die direct op het kind zijn gedefinieerd, komen in de tweede tabel terecht.

Een soortgelijk systeem is vereist bij het terugkoppelen naar de codebase vanuit de database. Een SQL JOIN kan worden gebruikt om alle records op te halen die overeenkomen met de basisklasse (uitgebreid), inclusief de onderliggende eigenschappen. De records die de onderliggende eigenschappen bevatten, worden dan toegewezen aan instanties van onderliggende klassen.

MAAK TABEL parent(Id INTEGER PRIMAIRE SLEUTEL, EEN INTEGER); MAAK TABEL child(ID INTEGER PRIMAIRE SLEUTEL, B INTEGER, ParentId INTEGER); klas Ouder { publieke functie __construct(int $A) {} }   laatste les Kind verlengt Ouder { publieke functie __construct(int $A, int $B) {} }   //Records ophalen //SELECT * FROM parent INNER JOIN child ON child.ParentId = parent.Id; $objs = []; foreach ($records als $record) { als (isset($record["B"])) { $objs[] = nieuw kind($record["A"], $record["B"]); } anders $objs[] = nieuw bovenliggend($record["A"]); }

De introductie van overerving vereist het gebruik van meer betrokken mapping-logica. Het onvermogen van relationele databases om de overervingsmogelijkheden van objectgeoriënteerde talen te modelleren, introduceert deze impedantiemismatch.

Zichtbaarheid en inkapseling

Een fundamenteel principe van objectgeoriënteerd programmeren is zichtbaarheid en inkapseling. Eigendommen worden als openbaar of privé verklaard. De interne representatie van een object kan worden verborgen achter een interface die gegevens vooraf opmaakt voor de consument.

Relationele databases hebben deze controles niet. Er is geen manier om een ​​veld als privé te declareren, en er is ook geen duidelijke noodzaak om dit te doen. Elk stukje gegevens dat in een database is opgeslagen, heeft zijn eigen doel; er mag geen redundantie zijn.

Advertentie

Dit is niet noodzakelijk waar wanneer het wordt omgezet naar een objectgeoriënteerd paradigma. Een object kan samen twee databasevelden gebruiken om een ​​nieuw stuk berekende informatie bloot te leggen. De waarden van de twee afzonderlijke velden zijn mogelijk niet relevant voor de toepassing en daardoor aan het zicht onttrokken.

MAAK TAFEL producten(Prijs INTEGER, Belastingtarief INTEGER); eindklasse Product {   publieke functie __construct( beschermd int $Price, beschermd int $TaxRate) {}   publieke functie getTotalPrice() : int { retourneer ($this -> Prijs * ($dit -> Belastingtarief/100)); } }

De applicatie geeft alleen om de totale productprijs, inclusief belastingen. De eenheidsprijs en het belastingtarief zijn ingekapseld in de productklasse. Zichtbaarheidscontroles (beveiligd) verbergen de waarden. De openbare interface bestaat uit een enkele methode die de twee velden gebruikt om een ​​nieuwe waarde te berekenen.

Meer in het algemeen pleit objectgeoriënteerd programmeren voor het programmeren naar interfaces. Directe toegang tot woningen wordt ontmoedigd. Door klassenmethoden te gebruiken die een interface implementeren, kunnen in de toekomst alternatieve implementaties worden gebouwd.

Er is geen directe tegenhanger hiervan in de relationele wereld. Databaseweergaven bieden een manier om tabellen en abstracte velden te combineren in nieuwe formulieren. U werkt echter nog steeds rechtstreeks met veldwaarden.

Samenvatting

Object-relationele impedantie-mismatches treden op wanneer een objectgeoriënteerde codebase gegevens uitwisselt met een relationele databank. Er zijn fundamentele verschillen in de manier waarop gegevens worden gemodelleerd. Dit vereist de introductie van een mapping-laag die gegevens tussen de formaten transponeert.

Het probleem van de impedantie-mismatch is een van de belangrijkste motiverende factoren bij de acceptatie van ORM's in objectgeoriënteerde talen. Deze maken de automatische hydratatie van complexe codebase-objecten uit relationele gegevensbronnen mogelijk. Zonder een speciale data mapping-laag hebben alleen de eenvoudigste applicaties een eenvoudig pad van en naar een relationele database.