Objektumorientált programozás

A Wikipédiából, a szabad enciklopédiából

Az objektumorientált programozás (angolul object-oriented programming, röviden OOP) egy programozási módszertan. Ellentétben a korábbi programozási módszertanokkal, nem a műveletek megalkotása áll a középpontban, hanem az egymással kapcsolatban álló programegységek hierarchiájának megtervezése. Az objektumorientált gondolkodásmód lényegében a valós világ modellezésén alapul – például egy hétköznapi fogalom, a „kutya” felfogható egy osztály (a kutyák osztálya) tagjaként, annak egyik objektumaként. Minden kutya objektum rendelkezik a kutyákra jellemző tulajdonságokkal (például szőrszín, méret stb.) és cselekvési képességekkel (például futás, ugatás). Az objektumorientált programozásban fontos szerep jut az úgynevezett öröklődésnek, ami az osztályok egymásból való származtatását teszi lehetővé: a kutyák osztálya származhat az állatok osztályából, így megörökli az állatok tulajdonságait és képességeit, valamint kibővítheti vagy felülírhatja azokat a kutyák tulajdonságaival, képességeivel.

Megközelítések[szerkesztés | forrásszöveg szerkesztése]

Analízisszintű gondolkodás[szerkesztés | forrásszöveg szerkesztése]

A szoftver fejlesztésének korai fázisaiban a megvalósítandó rendszer feladatait szeretnénk feltérképezni: a funkcionális és egyéb jellegű követelményeket. Más szóval, a kérdés ilyenkor az, hogy a rendszernek mit kellene tennie. Ilyenkor határozzuk meg a szoftver (formális és informális) specifikációját, majd abból kiindulva kezdjük magasabb szintű absztrakciók segítségével előállítani a rendszer modelljét, amely a konkrét megvalósítás alapját fogja képezni.

Tervezésszintű gondolkodás[szerkesztés | forrásszöveg szerkesztése]

A meglévő modell alapján a szoftver konkrét implementációjához (megvalósításához) vezető utat tervezzük meg. Ilyenkor arra keressük a választ, hogy a meghatározott specifikációt hogyan valósítsa meg a rendszer. Ezen a szinten már képbe kerülnek különböző alacsony szintű technikák is, mint például a kommunikációs protokollok, programozási nyelvek és technológiák.

Az OOP és a szekvenciális nyelvek különbségei[szerkesztés | forrásszöveg szerkesztése]

A hagyományos, ún. szekvenciális programozási nyelvekben az utasítások sorról sorra, egymást követően hajtódnak végre. Ez annyit jelent, hogy a program egyes sorai egymásra épülnek: Ha az egyik sorban definiálunk egy változót, akkor a következő sorban is használhatjuk. Ezt az egyszerűséget megtöri az előre definiált rutinok és függvények használata, de még a ciklusokkal, illetve más vezérlési szerkezetekkel együtt is könnyen átlátható a forráskód struktúrája. Az ilyen nyelveknél ez felfogható előnyként is, azonban nagy projektekben kényelmetlenséget okozhat, hogy egy-egy alapvető algoritmust többször, többféleképpen is le kell írnunk, holott lényegi változtatás nincs benne. Ezt a problémát részben lehet szubrutinokkal és függvényekkel orvosolni, de az igazi megoldást az objektumok használata jelenti.

Az objektumközpontú problémamegközelítés alapjaiban megváltoztatja a programozással kapcsolatos gondolkodásmódunkat. Az objektumorientált programozás alapja, hogy az adatokat és az őket kezelő függvényeket egy egységbe „zárjuk” (encapsulation – egységbezárás). Az OOP másik fontos sajátossága az öröklődés (inheritance). Az öröklés azt jelenti, hogy egy osztályból kiindulva újakat hozunk létre, amelyek öröklik az „ősosztály” (baseclass) adattagjait és metódusait. Az új osztályt származtatott (derived) osztálynak nevezzük.

Mik is az objektumok valójában?[szerkesztés | forrásszöveg szerkesztése]

Ha egy programkódban objektumokról beszélünk, először az osztályok felépítését kell megvizsgálni, ugyanis minden objektum egy előre definiált osztály példánya. Egy osztályban általában egy feladat elvégzéséhez szükséges kódrészleteket gyűjtik össze funkciójuk szerint, tagfüggvényekbe rendezve. Egy osztályt létrehozása után példányosítani kell, hogy használhatóvá váljanak a benne összegyűjtött rutinok. Az osztály példányát nevezzük objektumnak.

class A { }; //egy üres osztály

Az osztályok felépítése[szerkesztés | forrásszöveg szerkesztése]

A használt programozási nyelvtől függően, de legtöbbször a class előtétszóval definiálunk osztályokat. Egy osztály csak függvényeket (metódusokat, tagfüggvényeket) és változókat (adattagokat) tartalmazhat. Mivel az osztályokban található függvényeket az objektumon keresztül lehet elérni, ezért hívják őket tagfüggvényeknek, vagy metódusoknak. Bizonyos nyelvek megengedik, az osztály függvényeinek használatát példányosítás nélkül is (például a C++-ban a statikus függvények). Ilyen esetekben azonban a függvény meghívásához meg kell adni annak az osztálynak a nevét, amelynek a metódus tagja.

Minden osztálynak van legalább egy konstruktora. Ez egy különleges függvény, amely az osztály példányosításakor hívódik meg. Feladata a példány kezdőértékeinek beállítása, helyfoglalás a memóriában stb. Több konstruktort is megadhatunk, a fordító a szignatúrától függően választja ki a megfelelőt. A konstruktor párja a destruktor, ami az elfoglalt memóriát szabadítja fel, eltakarít maga után. Destruktorból pontosan egy darab van az osztályban. Néhány nyelvben (C#, Java) ún. „garbage collector”, „szemétgyűjtő” van, ami a program futása közben automatikusan szabadítja fel a nem használt memóriát.

Nyelvektől függően léteznek különböző osztályváltozók, melyek többnyire – a tagfüggvényekhez hasonlóan, csak az objektumon belül használhatóak. Például a C++ nyelvben ilyen a this változó (mutató), mely a példányosított osztály nevétől függetlenül mindig saját objektumára fog hivatkozni.

class A
{
 public:
  A() { this->msg = "Helló, világ!";} //konstruktor
 private:
  std::string msg;
};
 
A* obj = new A(); //példányosítás

Öröklődés[szerkesztés | forrásszöveg szerkesztése]

Egy osztály definiálása után előfordulhat, hogy az osztályban szereplő kódokat más osztályokban is használni szeretnénk. Például egy adatbázist, vagy mondjuk egy fájlkezelő függvényeket tartalmazó osztályt, valószínűleg más objektumokból is szeretnénk használni. Ehhez csak arra van szükség, hogy egy adott osztályt amiből a másik osztály tagfüggvényeit el akarjuk érni, abból származtassunk. Ezt nevezzük öröklődésnek.

class Base
{
 public:
  Base(){ };
  void f(){ };
};
 
class Derived : public Base
{
 public:
  Derived(){ };
};
 
Derived* der = new Derived();
der->f(); //A Derived osztály örökölte az f függvényt

Belátható, hogy az öröklődés használata rendkívül leegyszerűsíti a gyakran kellő függvények integrálását az egyes osztályokba anélkül, hogy meg kellene változtatni az osztályok struktúráját. Azokban a nyelvekben ahol esetleg nem valósították meg az öröklődést, van egy alternatív megoldás a problémára: Abban az osztályban, ahol használni szeretnénk egy másik osztály tagfüggvényét, egyszerűen példányosítanunk kell egy ősosztálybeli objektumot. Ennek a módszernek hátránya lehet, hogy egyes objektumokból esetleg több példány is lesz, ezáltal felesleges memóriát használ a programunk. Ezt kiküszöbölendő megtehetjük, hogy a használt osztályon kívül példányosítjuk a másik osztályt, és paraméterként adjuk át.

Nyilvánosság (PPP)[szerkesztés | forrásszöveg szerkesztése]

A PPP rövidítés az objektum orientált nyelvekben többnyire alkalmazott adattulajdonságok rövidítése. Angolul, sorrendben: public, protected, private – azaz: nyilvános, védett és saját. Ezen tulajdonságokat az objektum tagfüggvényei, illetve változói egyaránt felvehetik. Az egyes tulajdonságok az elemek nyilvánosságát, azaz hozzáférhetőségét határozzák meg a következő módon:

  • public: Az objektumot használó bármely kód számára közvetlenül hozzáférhető.
  • protected: Közvetlenül nem férhető hozzá, de a származtatott osztályok használhatják.
  • private: Csak abban az osztályban érhetők el, amelyikben meghatározták őket.

Felületek[szerkesztés | forrásszöveg szerkesztése]

A felületek, vagy más néven interfészek biztonsági segítséget jelentenek a nagyobb projektekben. Képzeljük csak el, mi történne, ha A objektum példányosításakor paraméterként átadunk neki egy másik, B objektumot, de B objektum nem valósítja meg hozzá fűzött reményeket, azaz nem tartalmaz egy változót, vagy függvényt, amire A osztálynak szüksége van! Az ilyen hibák felkutatása az OOP összetettsége miatt nem egyszerű, de felületek használatával elkerülhetőek.

A felület valójában előre meghatározza egy osztály felületét: Megadja a benne található tagfüggvényeket, azok nyilvánossági tulajdonságait, bemenő paramétereit, egyszóval a függvénytörzs kivételével mindent.

interface IF
{
 void f();
}

Egy ilyen felület úgy véd meg a fent említett hibáktól, hogy az osztály definiálásakor megadjuk, milyen felületet kell megvalósítania. Ha a definiált osztály nem illeszkedik a felületre a fordító hibát jelez, de elkerüljük a sokkal kellemetlenebb futásidőben bekövetkező hibát. A fenti interfész az alábbi osztály „csontváza”:

interface ItestInterface
{
 void f();
}
 
class ImplementationClass : ItestInterface
{
 void IF.f(){;}
}
 
ImplementationClass ic = new ImplementationClass();
ItestInterface itf = (ItestInterface) ic;
itf.f();

Elvont osztályok[szerkesztés | forrásszöveg szerkesztése]

Az elvont, vagy absztrakt osztályok átmenetet képeznek a hagyományos osztályok és az osztályokat meghatározó felületek között. Ez azt jelenti, hogy egy absztrakt osztály egyaránt tartalmaz kidolgozott, törzzsel rendelkező tagfüggvényeket, és előre nem meghatározott tagfüggvényeket, melyeket majd az osztályból származtatott alosztály fog részletesen definiálni. Az absztrakt osztály ily módon hagyományos értelemben vett osztályként és a tőle öröklő alosztályok interfészeként egyszerre tölt be funkciót.

class AbstractBase
{
 public:
  void printMsg() = 0;
  virtual ~AbstractBase();
};
 
class Derived : public AbstractBase
{
 public:
  Derived(){ };
  ~Derived(){ };
  void printMsg(){ std::cout << "MSG\n"; }
};

Tervezési minták[szerkesztés | forrásszöveg szerkesztése]

A tervezési minták lényegében azokra a problémákra nyújtanak általános megoldást, melyekkel a szoftverfejlesztők gyakran találkoznak. Ilyen probléma például, amikor egy adott környezetben már bevált kódot alkalmassá kell tennünk egy másik interfészen keresztül történő használatra is. Bár a probléma minden feladatnál egyedinek tűnik, egy idő után felismerjük, hogy a megoldási módszerek lényegében azonos sémát követnek. Így tehát, ha felfedjük egy probléma lényegét és összevetjük hasonló, már megoldott problémákkal, ugyanazokkal a lényegi lépésekkel találkozunk.

Kritikája[szerkesztés | forrásszöveg szerkesztése]

Számos ismert kutató és programozó vizsgálta az OOP hasznosságát. Íme, egy nem teljes lista:

  • Luca Cardelli egy tanulmányt írt "Az objektumorientált nyelvek hibás mérnöki tulajdonságai" címmel.[1]
  • Richard Stallman írta 1995-ben: "Az OOP bevezetése az Emacs-ben nem jár egyértelmű előnyökkel; használtam OOP-t, amikor Lisp számítógépek ablakozó rendszerén dolgoztam, és nem értek egyet azzal az állítással, hogy ez a programozásnak egy magasabb szintje lenne."[2]
  • Egy Thomas Potok és társai által készített tanulmány[3] nem mutatott jelentős eltérést a produktivitásban az OOP és a procedurális programozás között.
  • Christopher J. Date megállapította, hogy az OOP és más technológiák – különösen a relációsak – összehasonlítása nehéz, mert az OOP-nek nincs egy közösen elfogadott, egzakt definíciója.[4] Date és Darwen[5] javaslatot tett az OOP egy elméleti kiegészítésére, amely OOP-t használ mint testreszabható típusrendszert, amely támogatja a relációs adatbázisokat.
  • Alexander Stepanov szerint az OOP matematikailag korlátozott nézőpontot biztosít, és szerinte "majdnem akkora átverés, mint a mesterséges intelligencia. Látnom kéne legalább egy érdekes kódot, amit ezek az OO emberek írtak. ... Úgy gondolom, hogy az OOP filozófiája ingatag. Úgy gondolják, hogy minden dolog objektum. Még ha ez igaz is, nem túl érdekes tény – azt állítani, hogy minden objektum, olyan, mintha nem mondtunk volna semmit...".[6]
  • Paul Graham szerint az OOP célja, hogy egyfajta csordaszellemet képezzen, amely megakadályozza, hogy középszerű programozók középszerű cégeiknek túl nagy károkat okozzanak. Mindezt annak az árán, hogy cserébe lelassítja azoknak a programozóknak a munkáját, akik jobb vagy kompaktabb technikákat is ismernek.[7]
  • Joe Armstrong, az Erlang programozási nyelv feltalálója szerint "Az objektumorientált nyelvek problémája, hogy egy implicit környezetet is magukkal hoznak. Egy banánt kértem, de kaptam egy a kezében banánt tartó gorillát meg köré az egész dzsungelt."[8]
  • Richard Mansfield, a COMPUTE! magazin szerzője és korábbi szerkesztője szerint "Mint számtalan korábbi intellektuális divat ("fontosság", kommunizmus, "modernizmus" stb. — a történelem tele van ilyenekkel), az OOP velünk lesz, amíg végül a valóság igazolja magát. De figyelembe véve azt, amennyire az OOP elterjedt az egyetemeken és a munkahelyeken, valószínűleg hosszantartó illúziónak leszünk szemtanúi. Kiképzett programozók teljes generációi hagyják el a felsőoktatást az OOP-nek és semmi másnak szentelve az egész életüket."[9] Ugyancsak ő mondta a következőt: "Az OOP úgy viszonyul a programíráshoz, mint a reptéri biztonsági ellenőrzés a repüléshez."[10]
  • A funkcionális programozással való összehasonlításában írja Steve Yegge a következőt: "Az objektumorientált programozás a főneveket teszi minden más elé. Miért tennénk ennyi erőfeszítést ahhoz, hogy egy beszéd egy részét piedesztálra emeljük? Miért kéne egy bizonyos koncepciónak megelőzni bármi mást? Mintha az OOP szerint az igék kevésbé lennének fontosak, mint ahogy valójában gondolkodunk. Ez egy elég kitekert perspektíva."[11]
  • Rich Hickey, a Clojure nyelv megalkotója szerint az objektumalapú rendszerek a való világot túlzottan leegyszerűsítve mintázzák meg. Kiemeli, hogy az OOP-vel az időt nem lehet megfelelően modellezni, ami egyre problémásabb, ahogy a szoftverek fontosabbá válik a több szálon való futás lehetősége.[12]
  • Robert Harper, a Carnegie-Mellon Egyetem professzora Robert Harper 2011 márciusában írta a következőt: "Ebben a szemeszterben Dan Licatával közösen tartunk egy kurzust a funkcionális programozásról a jövendőbeli informatika szakosoknak... Az objektumorientált programozást kivettük a bevezető tantervből, mert természetéből adódóan nem moduláris és nem támogatja a párhuzamos feldolgozást, emiatt nem felel meg egy modern tantervnek. Akit mégis érdekel, a másodéves hallgatók részére ajánlunk egy kurzust az objektumorientált tervezésről."[13]
  • Részletes cikkében Lawrence Krubner végigveszi az objektumorientált programozás tizenkét aspektusát, és bebizonyítja, hogy más nyelvekhez hasonlítva (lisp, funkcionális nyelvek stb.) az OOP nyelveknek nincsenek különleges erősségeik, viszont szükségtelen komplexitást hordoznak magukkal.[14]

Lásd még[szerkesztés | forrásszöveg szerkesztése]

Irodalom[szerkesztés | forrásszöveg szerkesztése]

Külső hivatkozások[szerkesztés | forrásszöveg szerkesztése]


  1. Cardelli, Luca (1996.). „Bad Engineering Properties of Object-Oriented Languages”. ACM Comput. Surv. 28 (4es), 150. o, Kiadó: ACM. DOI:10.1145/242224.242415. ISSN 0360-0300. Hozzáférés ideje: 2010. április 21.  
  2. Stallman, Richard: Mode inheritance, cloning, hooks & OOP. Google Groups Discussion, 1995. január 16. (Hozzáférés: 2008. június 21.)
  3. Potok, Thomas, Mladen Vouk, Andy Rindos (1999.). „Productivity Analysis of Object-Oriented Software Developed in a Commercial Environment”. Software – Practice and Experience 29 (10), 833–847. o. DOI:<833::AID-SPE258>3.0.CO;2-P 10.1002/(SICI)1097-024X(199908)29:10<833::AID-SPE258>3.0.CO;2-P. Hozzáférés ideje: 2010. április 21.  
  4. C. J. Date, Introduction to Database Systems, 6th-ed., Page 650
  5. C. J. Date, Hugh Darwen. Foundation for Future Database Systems: The Third Manifesto (2nd Edition)
  6. Stepanov, Alexander: STLport: An Interview with A. Stepanov. (Hozzáférés: 2010. április 21.)
  7. Graham, Paul: Why ARC isn't especially Object–Oriented.. PaulGraham.com. (Hozzáférés: 2009. november 13.)
  8. Armstrong, Joe. In Coders at Work: Reflections on the Craft of Programming. Peter Seibel, ed. Codersatwork.com, Hozzáférés ideje: 2009. november 13.
  9. Mansfield, Richard. "Has OOP Failed?" 2005. Elérhető: 4JS.com, Hozzáférés ideje: 2009. november 13.
  10. Mansfield, Richard. "OOP Is Much Better in Theory Than in Practice" 2005. Elérhető: Devx.com Hozzáférés ideje: 2010. január 7.
  11. Stevey's Blog Rants
  12. Hickey, Rich, JVM Languages Summit 2009 vitaindító, Are We There Yet? 2009. november
  13. Teaching FP to Freshmen, Harper informatikaoktatással foglalkozó blogjáról.[1]
  14. Krubner, Lawrence: Object Oriented Programming is an expensive disaster which must end. smashcompany.com. (Hozzáférés: 2014. október 14.)