A Modula2 programozási nyelv

Objektum-orientált programozás



Objektum-orientált programozás

Objektumok

A nyelv objektum orientált kiterjesztése, az Object Oriented Modula-2 (OOM-2) ad eszközöket az objektum elvû programfejlesztéshez. Az osztályok deklarációjában felsorolhatók az új (konstans) attribútumok, az új és újradefiniált metódusok, az ôsosztály azonosítója és lehet itt egy inicializációs rész is. A publikus komponenseket a REVEAL kulcsszó után kell felsorolni. Példányok létrehozása a CREATE eljárással történik, ennek hatására a példányok számára szükséges dinamikus memória lefoglalásra kerül, valamint az  osztályok inicializációs része fut le. Ez az inicializációs rész a konstruktor szerepét tölti be és ez szintaktikailag a metódusokon kívül, azok után írt BEGIN...END blokkban elhelyezkedõ utasítássorozat. A DESTROY pedig megsemmisíti az objektumot.
Ekkor, ha van a BEGIN..END blokkban FINALLY rész, akkor az lefut (destruktornak megfelelõ viselkedés). Az osztályok READONLY-val jelölt attribútumai csak olvashatóak. Például:

MODULE Example;

CLASS Ellipse;
REVEAL SetCenter, SetAxes, Area, dimenzio; (* ezek láthatóak *)

  VAR major, minor: REAL;  (* mind a 4 komponens rejtett *)
  VAR x, y: REAL;

  CONST dimenzio = 2; (* az alakzatunk két dimenziós *)

  PROCEDURE SetCenter (xcoord, ycoord: REAL);
  BEGIN
    x:=xcoord;
    y:=ycoord;
  END SetCenter;

 PROCEDURE Area() : REAL;
 BEGIN
    .....
 END Area;

.....

 BEGIN  (* Inicializációs rész *)
  SetCenter(0.0);
  radius:=0.0;
 END Ellipse;

VAR ell: Ellipse;

BEGIN (* A fõprogram itt kezdõdik *)
  CREATE( ell );
  ell.SetCenter(1.2, 5.6);

....

END Example.
 

 Objektumokat egymásnak értékül adhatunk és vizsgálhatjuk az egyenlõségüket. Ezek a mûveletek egyszerûen a referenciák közötti mûveleteknek felelnek meg.Az EMPTY referencia érték jelenti a nem inicializált objektumot, hasonló a szerepe, mint a NIL pointernek a mutatók között.
 Az ADT-k megvalósítására használt technika osztályoknál is mûködik: az osztály leírása két külön részre bomlik, amelyet külön-külön file-ban kell tárolni. A definíciós modulban nem írunk metódusoknak törzset és csak a publikus metódusok deklarációit szerepeltetjük itt, az attribútumokkal hasonló a helyzet. Az implementációs modul csak a törzset tartalmazza: a privát attribútumokat és a publikus és privát metódusok implementációját, a publikus attributumokat tehát nem kell itt is leírni. Például:

DEFINITION MODULE Shapes;

CLASS Ellipse;
REVEAL SetCenter,  SetAxes,  Area,   dimension; (* ezek láthatóak *)

  VAR major, minor: REAL;  (* mind a 4 komponens rejtett *)
  VAR x, y: REAL;

  CONST dimension = 2; (* az alakzatunk két dimenzios *)

  PROCEDURE SetCenter (xcoord, ycoord: REAL);
  PROCEDURE Area() : REAL;

       (* Sikerült-e beállítani a tengelyek hosszát *)
  PROCEDURE SetAxes(a, b: REAL) : BOOLEAN;

 .....

END Ellipse;
END Shapes.

 Az implementációs modulba kerûlnek a metódusok tôrzsei:

IMPLEMENTATION MODULE Shapes;

CLASS Ellipse;
 PROCEDURE SetCenter (xcoord, ycoord: REAL);
  BEGIN
    x:=xcoord;
    y:=ycoord;
  END SetCenter;

 PROCEDURE Area() : REAL;
 BEGIN
    .....
 END Area;

......

END Ellipse;
END Shapes.

Öröklődés

 Az öröklõdéshez használt kulcsszó az INHERIT, mely után a szülõ osztály azonosítója következik.A szabvány OOM-2 esetében a többszörös öröklõdéssel járó kellemtlenségek fel sem merülnek: az csak az egyszeres öröklôdést támogatja. A leszármazott osztály a szülõ minden atrribútumához és metódusához hozzáfér, de az implementációs részben bevezetett (rejtett) komponensekhez nem fér hozzá.
 A gyerek osztály a szülõ attribútumait nem definiálhatja át, a metódusokat viszont igen, ilyenkor egy az eredeti metódussal megegyezõ interfészû eljárás jöhet szóba. Az átdefiniálsokat az OVERRIDE kulcsszó vezeti be. Szülõ metódusára minõsített nevekkel hivatkozhatunk, ez nem csak a közvetlen szülõre, hanem az öröklõdési lánc minden osztályára igaz. A következõ példában az ellipszisbõl származtatjuk a kört:

DEFINITION MODULE Shapes2;

FROM Shapes IMPORT Ellipse;

 CLASS Circle;
 INHERIT Ellipse;
 OVERRIDE PROCEDURE Area()  : REAL;
 OVERRIDE PROCEDURE SetAxes(a, b: REAL) : BOOLEAN;
 END Circle;

END Shapes2;

 Az implementációs modulban nem kell mégegyszer  kijelôlni a szülôosztályt. Csak az új metódus tôrzsét kell megadnunk.  :)
A mi példánkban kör esetén nincs szükség külön nagytengely hosszra (major) és kistengely hosszra (minor). A terület kiszámittásához most elég csak mondjuk a minor-t használni.

IMPLEMENTATION MODULE Shapes2;

FROM RealMath IMPORT pi;

CLASS Circle;
OVERRIDE PROCEDURE Area() : REAL;
BEGIN
  RETURN minor*minor*pi;
END Area;

OVERRIDE PROCEDURE SetAxes(a, b: REAL) : BOOLEAN;
BEGIN
 IF a<>b THEN
    RETURN FALSE;
 ELSE
     minor:=a;
     major:=b;
     RETURN TRUE;
  END;
  END SetAxes;

END Circle;

END Shapes2.
 

Absztrakt metódusok/osztályok

 Az ABSTRACT kulcsszóval jelölt metódusok az absztrakt metódusok. Egy osztály absztrakt, ha van legaláb egy absztrakt metódusa. Ha az osztaly absztrakt, akkor a CLASS kulcsszó elé is ki kell tenni az ABSTRACT kulcsszót.
Az implementációs részben tilos absztrakt metódusnak törzset írni. Ha csak absztrakt metódusunk van, akkor
elég ott csak az osztály üres deklarációját szerepeltetni.
 

Adatelrejtés

 Érdekesség, hogy a nyelv nem kulcsszavakkal támogatja az adatelrejtést, ehelyett szétválasztja az osztály import-export felületét a törzstôl. Amit a definíciós modulban deklarálunk, látható lesz kívülrôl; ez megfelel a public direktívának. Amit csak az implementációs modulban deklarálunk, azt kívülrôl nem látható; ez megfelel a private direktívának.