Prototípusra alapuló programozás
Ezt a szócikket némileg át kellene dolgozni a wiki jelölőnyelv szabályainak figyelembevételével, hogy megfeleljen a Wikipédia alapvető stilisztikai és formai követelményeinek. |
A prototípus-alapú programozás egy olyan objektumorientált programozási stílus, amelyben a viselkedés újrafelhasználása (öröklés) azon objektumok újrafelhasználásán keresztül történik, amelyek prototípusként szolgálnak. Ezt a modellt prototípusosnak, prototípus-orientáltnak, osztálymentesnek vagy példányalapúnak is nevezhetjük.
A prototípus-alapú programozás általánosított objektumokat használ, amelyeket később klónozni és kiterjeszteni lehet. Példaként vegyük a gyümölcsöket: egy "gyümölcs" objektum reprezentálja a gyümölcs tulajdonságait és funkcionalitását általánosságban. Egy "banán" objektum a "gyümölcs" objektumból klónozódna, és a banánokra jellemző általános tulajdonságokat kapcsolnánk hozzá. Minden egyes "banán" objektum a generikus "banán" objektumból klónozódna. Ezzel szemben az osztályalapú paradigmában egy "gyümölcs" osztályt egy "banán" osztály bővítene ki.
Az első prototípus-orientált programozási nyelv a Self volt, amit David Ungar és Randall Smith fejlesztett ki az 1980-as évek közepén az objektumorientált nyelvek tervezésére. A 90-es évek óta az osztálymentes paradigmája egyre népszerűbbé vált. Néhány jelenlegi prototípusorientált nyelv a JavaScript (és más ECMAScript implementációk, mint például a JScript és a Flash ActionScript 1.0), Lua, Cecil, NewtonScript, Io, Ioke, MOO, REBOL és AHK.
Tervezés és megvalósítás
[szerkesztés]A JavaScript prototípus öröklődését Douglas Crockford így írja le:
„You make prototype objects, and then … make new instances. Objects are mutable in JavaScript, so we can augment the new instances, giving them new fields and methods. These can then act as prototypes for even newer objects. We don't need classes to make lots of similar objects… Objects inherit from objects. What could be more object oriented than that?[1]”
A prototípus-alapú programozás támogatói szerint az ösztönzi a programozót arra, hogy először a példák valamelyik halmazának viselkedésére összpontosítson, és csak később aggódjon ezeknek az objektumoknak az archetipikus objektumokba való besorolásáról, amelyek később hasonlóan működnek az osztályokhoz.[2] Sok prototípus-alapú rendszer ösztönzi a prototípusok futási időben történő módosítását, míg csak nagyon kevés osztályalapú objektumorientált rendszer (például a dinamikus objektumorientált rendszer, Common Lisp, Dylan, Objective-C, Perl, Python, Ruby vagy Smalltalk) engedi meg az osztályok módosítását egy program végrehajtása közben.
Majdnem minden prototípus-alapú rendszer értelmezett és dinamikusan típusozott nyelveken alapul. A statikusan típusozott nyelveken alapuló rendszerek technikailag lehetségesek, bár az Omega nyelv, amelyet a Prototípus-alapú programozás[3] című munkában említenek, példa erre. Az Omega weboldala szerint még az Omega sem kizárólag statikus, hanem inkább "a fordító választhatja meg a statikus kötést, amikor lehetséges, és javíthatja a program hatékonyságát".
Objektum létrehozása
[szerkesztés]A prototípus-alapú nyelvekben nincsenek explicit osztályok. Az objektumok közvetlenül más objektumokból örökölnek egy prototípus tulajdonságon keresztül. A prototípus tulajdonságot Self és JavaScript esetében prototípusnak vagy proto-nak nevezik. Két módszer van az új objektumok létrehozására: az "ex nihilo" („semmiből”) objektum létrehozás vagy egy meglévő objektum klónozása. Az előbbit az objektum szó szerinti szintaxisa támogatja, amikor az objektumokat a {...} módon lehet definiálni futási időben, és közvetlenül átadhatók egy változónak. Míg a legtöbb rendszer támogat különböző klónozási módszereket, az "ex nihilo" objektum létrehozás nem olyan elterjedt. [4]
Az osztályalapú nyelvekben egy új példányt egy osztály konstruktorfüggvényén keresztül hoznak létre, amely egy blokk memóriát tart fenn az objektum tagjai (tulajdonságok és metódusok) számára, és visszaad egy hivatkozást erre a blokkra. Az opcionális konstruktor argumentumokat át lehet adni a függvénynek, és általában tulajdonságokban vannak tárolva. Az eredményezett példány minden olyan metódust és tulajdonságot örököl, amelyeket az osztályban definiáltak, mintegy sablonként, amelyből hasonló típusú objektumokat lehet létrehozni.
Azokban a rendszerekben, amelyek támogatják az "ex nihilo" objektum létrehozást, az új objektumok létrehozhatók nulláról, meglévő prototípustól való klónozás nélkül. Ezek a rendszerek különleges szintaxist biztosítanak az új objektumok tulajdonságainak és viselkedésének meghatározására, anélkül, hogy hivatkoznának meglévő objektumokra. Sok prototípusnyelvben létezik egy gyökér objektum, amelyet általában Objektumnak neveznek, és amely az alapértelmezett prototípusa az összes futási időben létrehozott más objektumnak, és olyan gyakran használt metódusokat tartalmaz, mint a toString(), amely egy leírást ad az objektumról stringként. Az "ex nihilo" objektum létrehozásnak egy hasznos aspektusa, hogy biztosítja, hogy az új objektumok slot (tulajdonságok és metódusok) nevei ne ütközzenek a legfelső szintű Objektum objektum névterével. (A JavaScript nyelvben ezt egy null prototípussal érhetjük el, azaz Object.create(null).)
Klónozás azt jelenti, hogy egy új objektumot létrehoznak egy meglévő objektum (prototípusa) viselkedésének másolásával. Az új objektum ezt követően magában hordozza az eredeti összes tulajdonságát. Ettől a ponttól kezdve a new objektum módosítható. Néhány rendszerben a létrejött gyermekobjektum explicit kapcsolatot tart fenn (delegáció vagy hasonlóság révén) a prototípusával, és a prototípusban bekövetkező változások megjelennek a klónban. Más rendszerek, például a Forth-szerű Kevo programozási nyelv, nem terjesztik ki a változást a prototípusról ezen a módon, és inkább egy konkatentatív modellt követnek, ahol a klónozott objektumokban történő változások nem terjednek automatikusan leszármazottakra. [5]
// Az objektum létrehozása a szó szerinti objektum jelöléssel {}.
const foo = { név: "foo", egy: 1, kettő: 2 };
// Egy másik objektum.
const bar = { kettő: "kettő", három: 3 };
// Az Object.setPrototypeOf() egy metódus, amelyet az ECMAScript 2015-ben vezettek be.
// A szimplaság kedvéért tegyük fel, hogy a következő sor működik az adott
// motortól függetlenül:
Object.setPrototypeOf(bar, foo); // foo most a bar prototípusa.
// Ha mostantól foo tulajdonságaihoz próbálunk hozzáférni bar-ból,
// sikerülni fog.
bar.egy; // Feloldódik 1-re.
// A gyermek objektum tulajdonságai is elérhetők.
bar.három; // Feloldódik 3-ra.
// A saját tulajdonságok elfedik a prototípus tulajdonságait.
bar.kettő; // Feloldódik "kettő"
bar.név; // érintetlen, feloldódik "foo"
foo.név; // Feloldódik "foo"
Egy másik példa:
const foo = { egy: 1, ketto: 2 };
// bar.prototype = foo const bar = Object.create(foo);
bar.harom = 3;
bar.egy; // 1
bar.ketto; // 2
bar.harom; // 3
Delegáció
[szerkesztés]A delegációt használó prototípus-alapú nyelvekben a nyelvi futási idő képes azonnal kiválasztani a megfelelő módszert vagy megtalálni a megfelelő adatelemet, egyszerűen követve a delegáció mutatóit (az objektumtól a prototípusáig) egyezésig. Mindaz, ami ehhez szükséges, az a delegáció mutatója. Ellentétben az osztályalapú objektumorientált nyelvek osztály és példány kapcsolatával, a prototípus és az abból származók kapcsolatának nem kell ahhoz hasonló memória- vagy szerkezeti hasonlósággal rendelkeznie, mint az eredeti. Emiatt a gyermekobjektumot továbbra is módosíthatják és kiegészíthetik az idő múlásával, anélkül, hogy átrendeznék az ehhez kapcsolódó prototípust, mint az osztályalapú rendszerekben. Fontos megjegyezni, hogy nem csak adatok, hanem metódusok is hozzáadhatóak és változtathatóak.
Összefűzés (konkatenálás)
[szerkesztés]A konkatenatív prototípusozásban - amelyet a Kevo programozási nyelv alkalmaz - nincsenek látható mutatók vagy hivatkozások az eredeti prototípusra, amelyből egy objektum klónozódik. A prototípus (szülő) objektum másolva van, nem pedig hivatkozáson alapul, és nincs delegáció. Ennek eredményeként a prototípuson végrehajtott változások nem tükröződnek vissza a klónozott objektumokban.[6] Egyébként a Cosmos programozási nyelv ugyanezt éri el az állandó adatszerkezetek használatával.[7]
Ezen elrendezés alapján a fő koncepcionális különbség az, hogy a prototípus-objektumra tett változások nem terjednek automatikusan tovább a klónokra. Ezt előnynek vagy hátránynak tekinthetjük. (Azonban a Kevo további alapműveleteket is biztosít a változások közzétételéhez az objektumok halmazaiban az hasonlóságuk alapján - úgynevezett családi hasonlóságok vagy klón család mechanizmus[8] - nem a taxonómiai eredet alapján, ahogyan azt a delegációs modell esetében szokás.) Néha azt is állítják, hogy a delegáció alapú prototípusozásnak az a további hátránya is van, hogy a gyermekobjektumokra tett változások befolyásolhatják a szülő objektum későbbi működését. Azonban ez a probléma nem velejárója a delegáció alapú modellnek, és nem létezik a JavaScript delegáció alapú nyelvekben, amelyek biztosítják, hogy a gyermekobjektumra tett változások mindig a gyermekobjektumban legyenek rögzítve, sosem a szülőben (azaz a gyermek értéke elfedi a szülő értékét, ahelyett hogy megváltoztatná a szülő értékét).
Az egyszerű implementációkban a konkatenatív prototípusozás gyorsabb tag-keresést eredményezhet, mint a delegáció alapú prototípusozás (mert nincs szükség a szülőobjektum láncolására), de viszont több memóriát használ (mert minden helyet másolnak, nem pedig egyetlen helyen van egy mutató a szülőobjektumra). Azonban a problémát kifinomultabb implementációk is elkerülhetik, bár sebesség és memória közötti kompromisszumokra van szükség. Például a konkatenatív prototípusozással rendelkező rendszerek alkalmazhatnak egy másolás-írás implementációt a háttérben történő adatmegosztás lehetővé tétele érdekében - és egy ilyen megközelítést tényleg alkalmaz a Kevo is.[9] Másrészt a delegáció alapú prototípusozással rendelkező rendszerek gyorsítótárazást is alkalmazhatnak az adatkeresés felgyorsítása érdekében.
Kritika
[szerkesztés]Az osztályalapú objektummodellek hívei, akik kritizálják a prototípus-alapú rendszereket, gyakran olyan aggodalmakkal rendelkeznek, amelyek hasonlóak a statikus típusrendszerrel rendelkező programozási nyelvek dinamikus típusrendszerével kapcsolatos aggályokhoz (lásd adattípus). Általában ilyen aggodalmak az érvényesség, biztonság, kiszámíthatóság, hatékonyság és a programozók ismeretlensége köré csoportosulnak.
Az érvényesség, biztonság és kiszámíthatóság tekintetében az osztályokat gyakran analógoknak tekintik a típusokhoz (a legtöbb statikus típusú objektumorientált nyelvben ezt a szerepet töltik be), és azt állítják, hogy szerződéses garanciákat nyújtanak az eseteikre és az eseteik felhasználóira nézve, hogy bizonyos módon fognak viselkedni.Az érvényesség, biztonság és kiszámíthatóság tekintetében az osztályokat gyakran analógoknak tekintik a típusokhoz (a legtöbb statikus típusú objektumorientált nyelvben ezt a szerepet töltik be), és azt állítják, hogy szerződéses garanciákat nyújtanak az eseteikre és az eseteik felhasználóira nézve, hogy bizonyos módon fognak viselkedni.
Az hatékonyság tekintetében az osztályok deklarálása egyszerűsíti a sok olyan fordítóoptimalizációt, amelyek lehetővé teszik a hatékony módszer- és példányváltozó keresést. A Self nyelv esetében sok időt fordítottak a prototípus-alapú rendszerek teljesítményének fejlesztésére, fordítására és értelmezésére az osztályalapú rendszerekkel szemben.
A prototípus-alapú nyelvek ellen gyakran az a vád merül fel, hogy a szoftvertervező közösség nem ismeri őket, annak ellenére, hogy a JavaScript népszerűsége és piaci áthatolása ellenére. Azonban a prototípus-alapú rendszerek ismerete nő a JavaScript keretrendszerek terjedésével és a JavaScript bonyolult használatával, ahogy a World Wide Web (Web) érik.[10] Az ECMAScript 6 osztályokat vezetett be szintaktikus cukorként a meglévő JavaScript prototípus-alapú öröklés fölé, alternatív módot nyújtva az objektumok létrehozásához és az öröklés kezeléséhez.[11]
Prototípus-alapú programozást támogató nyelvek
[szerkesztés]
- Actor-Based Concurrent Language (ABCL): ABCL/1, ABCL/R, ABCL/R2, ABCL/c+
- Agora
- AutoHotkey
- Cecil and Diesel of Craig Chambers
- ColdC
- COLA
- Common Lisp
- Cyan
- ECMAScript
- ActionScript 1.0, used by Adobe Flash and Adobe Flex
- ECMAScript for XML (E4X)
- JavaScript
- JScript
- TypeScript
- Io
- Ioke
- Jsonnet
- Logtalk
- LPC
- Lua
- M2000
- Maple
- MOO
- Neko
- NewtonScript
- Nim
- Nix
- Object Lisp
- Obliq
- Omega
- OpenLaszlo
- Perl, with the Class::Prototyped module
- Python with prototype.py.
- R, with the proto package
- REBOL
- Red (programming language)
- Ruby (programming language)
- Self
- Seph
- Slate (programming language)
- SmartFrog
- Snap!
- Etoys
- TADS
- Tcl with snit extension
- Umajin[12]
Hivatkozások
[szerkesztés]- ↑ Crockford, Douglas: Prototypal Inheritance in JavaScript. (Hozzáférés: 2021. június 22.)
- ↑ Taivalsaari, Antero. Section 1.1, Classes vs. Prototypes: Some Philosophical and Historical Observations, 44–50. o. (1996)
- ↑ Blaschek, Günther. Section 2.8, Omega: Statically Typed Prototypes, 177. o.
- ↑ Dony, Chistophe. Section 1.2, Classifying Prototype-based Programming Languages, 17. o.
- ↑ Taivalsaari, Antero. Section 1.1, Classes vs. Prototypes: Some Philosophical and Historical Observations, 44–50. o. (1996)
- ↑ Antero Taivalsaar: Simplifying JavaScript with Concatenation-Based Prototype Inheritance (angol nyelven). Tampere University of Technology, 2009 [2011. augusztus 13-i dátummal az eredetiből archiválva]. (Hozzáférés: 2015. március 11.) „Kevo implemented a pure concatenation-based object model in which new objects were created by copying and the namespaces of all the objects were always fully self-contained. … Furthermore, Kevo had an internal clone family mechanism that made it possible to track the “genealogy” of changes among groups of objects, so that changes to individual objects could be propagated to other objects when necessary.”
- ↑ Object‐Oriented Programming (angol nyelven). GitHub . (Hozzáférés: 2023. szeptember 4.)
- ↑ Antero Taivalsaar: Simplifying JavaScript with Concatenation-Based Prototype Inheritance (angol nyelven). Tampere University of Technology, 2009 [2011. augusztus 13-i dátummal az eredetiből archiválva]. (Hozzáférés: 2015. március 11.) „Kevo implemented a pure concatenation-based object model in which new objects were created by copying and the namespaces of all the objects were always fully self-contained. … Furthermore, Kevo had an internal clone family mechanism that made it possible to track the “genealogy” of changes among groups of objects, so that changes to individual objects could be propagated to other objects when necessary.”
- ↑ Taivalsaari, Antero (1992). „Kevo, a prototype-based object-oriented programming language based on concatenation and module operations”. Technical Report Report LACIR 92-02, Kiadó: University of Victoria.
- ↑ „Prototypal Object-Oriented Programming using JavaScript”, A List Apart, 2016. április 26. (Hozzáférés: 2018. október 21.) (amerikai angol nyelvű)
- ↑ Classes. JavaScript reference . Mozilla Developer Network. (Hozzáférés: 2016. február 9.)
- ↑ Proprietary scripting language. http://www.davidbrebner.com/?p=4 has some basic examples of use.
Fordítás
[szerkesztés]Ez a szócikk részben vagy egészben a Prototype-based programming című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.
További irodalom
[szerkesztés]- Abadi, Martin. A Theory of Objects. Springer-Verlag (1996). ISBN 978-1-4612-6445-3
- Class Warfare: Classes vs. Prototypes, by Brian Foote.
- szerk.: Noble: Prototype-Based Programming: Concepts, Languages and Applications. Springer-Verlag (1999). ISBN 981-4021-25-3
- Using Prototypical Objects to Implement Shared Behavior in Object Oriented Systems, by Henry Lieberman, 1986.