Prototype programmering

Den aktuelle version af siden er endnu ikke blevet gennemgået af erfarne bidragydere og kan afvige væsentligt fra den version , der blev gennemgået den 13. december 2019; checks kræver 3 redigeringer .

Prototypeprogrammering  er en stil med objektorienteret programmering , hvor der ikke er noget begreb om en klasse , og nedarvning sker ved at klone en eksisterende forekomst af et objekt  - en prototype .

Det kanoniske eksempel på et prototype-orienteret sprog er Self . I fremtiden begyndte denne programmeringsstil at vinde popularitet og var grundlaget for programmeringssprog som JavaScript , Lua , Io , REBOL osv.

Sammenligning med den klasseorienterede tilgang

På sprog baseret på begrebet "klasse" er alle objekter opdelt i to hovedtyper - klasser og instanser . En klasse definerer en struktur og funktionalitet ( adfærd ), der er den samme for alle forekomster af den pågældende klasse. En instans er en databærer - det vil sige, den har en tilstand , der ændres i henhold til den adfærd, der er defineret af klassen.

Tilhængere af prototypisk programmering hævder ofte, at klassebaserede sprog fører til en overvægt på klassernes taksonomi og forholdet mellem dem. I modsætning hertil fokuserer prototyping på adfærden af ​​et (lille) antal "mønstre", som derefter klassificeres som "basale" objekter og bruges til at skabe andre objekter. Mange prototype-orienterede systemer understøtter ændring af prototyper under kørsel, mens kun en lille del af klasseorienterede systemer (f.eks. Smalltalk , Ruby ) tillader klasser at blive ændret dynamisk.

Selvom langt de fleste prototype-baserede systemer er baseret på dynamisk typede fortolkede sprog, er det teknisk muligt også at tilføje prototyping til statisk typekontrollerede sprog. Omega - sproget er et eksempel på et sådant system.

Objektkonstruktion

I klasseorienterede sprog oprettes en ny instans ved at kalde klassekonstruktøren (måske med et sæt parametre). Den resulterende instans har strukturen og adfærden hårdkodet af sin klasse.

Prototypesystemer giver to metoder til at skabe et nyt objekt: kloning af et eksisterende objekt eller oprettelse af et objekt fra bunden . For at skabe et objekt fra bunden, er programmøren forsynet med syntaktiske midler til at tilføje egenskaber og metoder til objektet. I fremtiden kan en komplet kopi af det - en klon - fås fra det resulterende objekt. Under kloningsprocessen arver kopien alle egenskaberne ved sin prototype, men fra det øjeblik bliver den uafhængig og kan ændres. I nogle implementeringer lagrer kopier referencer til prototypeobjekter, og delegerer noget af deres funktionalitet til dem; mens ændring af prototypen kan påvirke alle dens kopier. I andre implementeringer er nye objekter fuldstændig uafhængige af deres prototyper. Begge disse tilfælde diskuteres nedenfor.

//Et eksempel på arv i prototypisk programmering //på eksemplet med JavaScript-sproget //Opret et nyt objekt lad foo = { name : "foo" , one : 1 , two : 2 }; //Oprettelse af endnu et nyt objekt lad bar = { two : "to" , three : 3 }; bar . __proto__ = foo ; // foo er nu prototypen til bar //Hvis vi nu forsøger at få adgang til felterne i foo fra bar //vil det virke bar . en // Er lig med 1 //Tilpassede felter er også tilgængelige bar . tre // Er lig med 3 //Tilpassede felter har højere forrang end prototypefelter . to ; // Er lig med "to"

Delegation

I prototype-orienterede sprog, der bruger delegering , er runtime i stand til at sende metodekald (eller slå de rigtige data op) ved blot at følge kæden af ​​delegerende pointere (fra et objekt til dets prototype), indtil et match er lavet. I modsætning til klasse-instans-forholdet kræver prototype-barn-forholdet ikke, at efterkommerobjekter bevarer strukturel lighed med deres prototype. Over tid kan de tilpasse og forbedre sig, men der er ingen grund til at redesigne prototypen. Det er vigtigt, at du kan tilføje / slette / ændre ikke kun data, men også funktioner, mens funktioner også viser sig at være objekter på det første niveau . Som et resultat refererer de fleste prototype-orienterede sprog til objektets data og metoder som "slots" (celler).

Cascading

I "ren" prototyping - også kaldet cascading og introduceret i Kevo  - gemmer klonede objekter ikke referencer til deres prototyper. Prototypen kopieres en-til-en med alle metoder og attributter, og kopien tildeles et nyt navn (reference). Det ligner mitosen af ​​biologiske celler.

Blandt fordelene ved denne tilgang er det faktum, at skaberen af ​​kopien kan ændre den uden frygt for bivirkninger blandt andre efterkommere af hans forfader. De beregningsmæssige omkostninger ved afsendelse er også drastisk reduceret, da der ikke er behov for at gå gennem hele kæden af ​​mulige delegerede på jagt efter en passende slot (metode eller attribut).

Ulemper omfatter vanskeligheder med at udbrede ændringer til systemet: ændring af en prototype ændrer ikke umiddelbart og automatisk alle dens efterkommere. Kevo giver dog yderligere midler til at publicere ændringer blandt flere objekter baseret på deres lighed ("familielighed") snarere end på tilstedeværelsen af ​​en fælles forfader, hvilket er typisk for modeller med delegation.

En anden ulempe er, at de enkleste implementeringer af denne model fører til et øget (sammenlignet med delegationsmodellen) hukommelsesforbrug, da hver klon, indtil den ændres, vil indeholde en kopi af dens prototypedata. Dette problem kan dog løses ved optimal adskillelse af uændrede data og brug af " lazy copy " - som blev brugt i Kevo.

Kritik

Tilhængere af klasseorienterede objektmodeller, der kritiserer den prototypiske tilgang, bekymrer sig ofte om de samme problemer, som statiske maskinskrivere bekymrer sig om dynamisk indtastede sprog. Især kredser diskussioner om emner som korrekthed , sikkerhed , forudsigelighed og programeffektivitet .

Med hensyn til de første tre punkter behandles klasser ofte som typer (og de er faktisk i de fleste statisk typede objektorienterede sprog), og klasser formodes at give visse konventioner og garantere, at instanser vil opføre sig på en veldefineret måde. .

Med hensyn til effektivitet forenkler deklaration af klasser i høj grad compilerens optimeringsopgave, hvilket gør både metoder og attributopslag på instanser mere effektive. I tilfældet med selvsproget blev meget af tiden brugt på at udvikle kompilerings- og fortolkningsteknikker , der ville bringe ydeevnen af ​​prototypebaserede systemer tættere på deres klasseorienterede konkurrenter. Yderligere arbejde i denne retning, såvel som fremskridt i teorien om JIT-kompilatorer, har ført til det faktum, at forskellen mellem klasseorienterede og prototypeorienterede tilgange på nuværende tidspunkt har ringe effekt på effektiviteten af ​​den resulterende kode. Især den prototypebaserede Lua er et af de hurtigst fortolkede sprog og konkurrerer direkte med mange kompilerede, [1] og Lisaac -sprogoversætteren genererer ANSI C -kode , der er næsten lige så god som native. [2]

Endelig er den måske mest almindelige kritik mod prototypeprogrammering, at softwareudviklingssamfundet ikke er fortroligt nok med det, på trods af JavaScripts popularitet og udbredelse . Fordi prototype-baserede systemer er relativt nye og stadig få og langt imellem, er udviklingsteknikker, der bruger dem, endnu ikke blevet udbredt.

Sprog

Noter

  1. Hvilke programmeringssprog er hurtigst? Arkiveret 28. juni 2011 ved Wayback Machine Computer Language Benchmarks Game.
  2. Lisaac vs. GNU C++ (utilgængeligt link) . Hentet 4. september 2010. Arkiveret fra originalen 20. december 2008. 

Litteratur

  • Ian Graham. Objektorienterede metoder. Principper og praksis = Objektorienterede metoder: Principper og praksis. - 3. udg. - M . : "Williams" , 2004. - S. 880. - ISBN 0-201-61913-X .

Links