You are on page 1of 41

AZ OOP ALAPJAI

OOP vs struktúrálatlan
programozás


Az objektum-orientált programozás a klasszikus
struktúrált programozásnál jóval hatékonyabb
megoldást képes nyújtani a legtöbb problémára.

Az osztályok újrafelhasználásának támogatásával
nagymértékben tudja csökkenteni a szoftverek
fejlesztéséhez szükséges időt.

Az objektumorientált programozás abban különbözik
leginkább a struktúrálatlan programozási módszerektől,
hogy a programrészeket, hasonló feladatokat, de főleg
hasonló feladatokon dolgozó adatokat és az azokat
felhasználó metódusokat csokorba foglaljuk.

Az objektum-orientált programozás jobban igyekszik
közelíteni a világban lejátszódó valódi folyamatokhoz.
Az OOP alapfogalmai


Osztály

Objektum, példány, egyed

Osztálydefiníció
 példányváltozók
 osztályváltozók
 metódusok
 konstruktor
 destruktor
 inicializáló blokk

Hozzáférési jogok

Egységbezárás

Adatelrejtés
Osztály létrehozása

Egy egyed egy osztály megvalósítása, más
szóval példányosítása. Javaban ezt így érjük
el:
Object objektum = new Object()

Ilyenkor lefut az osztály konstruktora, ahol
meghatározhatjuk a kezdőértékeket,
inicializálhatjuk az objektumot.

Egy osztálynak lehetnek példányváltozói, illetve
osztályváltozói. Előbbiből minden egyes
példányosított egyedhez kerül egy-egy, míg
osztályváltozóból az összes azonos osztályból
példányosított egyedhez csak egy. Ugyanez
érvényes az eljárásokra is.

Java esetén egy osztály definíciója és
deklarációja, azaz az eljárások feje és
megvalósítása nem szétválasztható, mint
például C++-ban.
Példa - Autó


Valósítsunk meg egy Autó osztályt
Javaban!
package pelda002; // az osztályt tartalmazó csomag
public class Auto { //az osztály kezdete
// az osztály megvalósítása
} //az osztály vége
Autó

- benzinár: int
- tipus: String
- km_ora: double
- benzin: double
- ferohely: int
+Auto(tipus: String, fogyasztas: double,
ferohely: double)
+Auto(tipus: String, fogyasztas: double,
ferohely: double, km_ora: double)
+költség(km: double): double
+fuvar (km: double)
+tankol (l: double)
+toString(): String
Példa – Autó - változók


Ahogy C++-ban, úgy a Javában is felsorolhatunk
változókat, de a Java megengedi, hogy iniciáljuk is azokat.

Változó deklarációja:
[módosítók] típus változó [inicializáció]

public class Auto {


static private int benzinar=250; //statikus típus
private String tipus;
private double benzin;
private double fogyasztas;
private double km_ora=0; //példa kezdőértékre

private int ferohely;


Példa – Autó - Konstruktor


Minden osztály példányosításakor lefut egy
konstruktor. Ennek neve – ahogy C++-ban is
– megegyezik az osztály nevével, és nincs
visszatérési értéke.

Minden osztálynak létezik konstruktora,
legfeljebb az üres, mégha nem is hozzuk
létre, lefut.

Konstruktorból lehet több is, túlterhelésükre
ugyanaz vonatkozik, mint a függvények
túlterhelésére.
Példa – Autó - Konstruktor
public Auto(String tipus, double fogyasztas, int ferohely){
this.tipus=tipus;
this.fogyasztas=fogyasztas;
this.km_ora=0;
this.benzin=0;
this.ferohely=ferohely;
}

public Auto(String tipus, double fogyasztas, int ferohely, double km_ora){


this.tipus=tipus;
this.fogyasztas=fogyasztas;
this.km_ora=km_ora;
this.benzin=0;
this.ferohely=ferohely;
}
Példa – Autó - Metódusok

 Érdekesség, hogy a metódus neve


megegyezhet egy változóéval is.
 Az osztály metódusait, ahogy láttuk a
konstruktornál, szintén túl lehet terhelni.
 Metódus definíciója:
[módosítók] típus Név([paraméterek]) {törzs}
 Példa metódusokra:
Példa – Autó - Metódusok

Az alábbi függvények dokumentációja és
magyarázata a külön dokumentumban található

public void tankol(double l){


benzin+=l;
}

private double benzinigeny(double km){


return ((double)km/100)*fogyasztas;
}

public double koltseg(double km){


return benzinigeny(km)*benzinar;
}
Példa – Autó - Metódusok

public double halad(double km) {


if(benzinigeny(km)<=benzin){
benzin-=benzinigeny(km);
km_ora+=km;
System.out.println("Megtettunk " + km + "km utat!");
return km;
}
else {
System.out.println("Nincs benzin " +km+ "km uthoz!");
return 0;
}
}
Példa – Autó – Getter & Setter

Objektumok leírásánál legtöbbször elrejtjük a belső
változókat a külvilág elől, mert pl nem akarjuk, hogy
változtassák, módosítottan akarjuk megjeleníteni
vagy átadni, vagy egyszerűen nem akarjuk, hogy
lássák. Ezért is lettek private változók. Ilyenkor
használatosak a be- és kiviteli függvények, a
getterek és setterek. Most az előbbire látunk
példát:


public double benzin_ora(){
return benzin;
}

public double km_ora() {


return km_ora;
}
Példa – Autó – String toString()


A Javában minden egyednek van egy függvénye,
ami szöveges információt hordoz a példányról,
ez a public String toString() függvény, amit ha
nem hozunk létre, az objektumunk örököl az
ősosztálytól (erről bővebben később).
public String toString(){
return tipus + ", benzin: " + benzin_ora() + ",
km: " + km_ora();
}
További osztály-elemek
(említés szintjén, a példába ne
foglaljuk őket):

inicializációs blokk (vagy blokkok), ami még a
konstruktor előtt lefut, és azokon a változókon
dolgozhat, amiket már előtte definiáltunk (mindez a az
osztály törzsében, metóduson kívül).
String s0;
{
s0 = new String("es-null"); // inic. blokkon kívül
ezt nem szabadna!
}

Javában a Garbage-collector elvégzi helyettünk a
memória tisztítását, de néha szükség lehet valamiféle
destruktor jellegű metódusra. Erre szolgál a Finalize,
illetve a classFinalize metódus:

protected void Finalize() throws Throwable {}

static void classFinalize() throws Throwable {}
Módosítók összessége

Osztály:

public: Az osztály bárki számára látható

final: Végleges, nem lehet tovább
bővíteni. Az öröklődésnél lesz róla szó
bővebben.

abstract: Az öröklődésnél lesz róla szó,
csak bővíteni lehet, példányosítani nem.

(Üres): Üres gyakorlatilag úgy
használható, mint a public, a csomagra
vonatkozóan
Módosítók összessége

Változó, illetve objektum:


 public: Az objektumot használó bármely
kód számára közvetlenül hozzáférhető.
 protected: Private, de az alosztályok
látják
 private: Csak azon objektum számára
elérhetők, melyben meghatározták őket.
 final: Végleges, azaz konstans érték
 static: Osztályváltozó, egy osztályhoz
csak egy tartozik
Módosítók összessége
Metódus esetén:

public: Az objektumot használó bármely kód
számára közvetlenül hozzáférhető.

protected: Közvetlenül nem, csak egy öröklés általi
alosztályon keresztül érhető el.

private: Csak azon objektum számára elérhetők,
melyben meghatározták őket.

static: Példányosítás nélkül használható, (pl println
fv), csak statikus változókat használhat.

final: Végleges, a leszármazott nem írhatja felül.
(Öröklődésnél bővebben)

abstract: Absztrakt osztálynál használható,
kötelező felülírnia, azaz megvalósítania a
leszármazott osztálynak.
Öröklődés

 Tegyük fel, hogy létre akarunk hozni:


 Autót (már megvan)
 Taxit
 Buszt
 Ez így egy kicsit sok, főleg hogy az adatok
és metódusok nagy része ismétlődne.
 Megoldás: bővítsük ki az Autót a Taxi
jellemzőivel! = specializáljunk!
Öröklődés a Javában
 A leszármazott osztály örökli a szülő minden
tulajdonságát.
 A szülő private tagjaiból is van példánya, de
nem férhet hozzájuk közvetlenül (erre van a
protected).
 Valójában Jávában minden objektum
származtatott, az ősosztály java.lang.Object
kiterjesztettje.
 Jávában a kiterjesztést az extend szóval
jelölhetjük.
 A leszármazott a szülőobjektum egyes tagjaira
a super kulcsszóval hivatkozhat.
 Object metódusai: equals, getClass, toString,
stb
Az Auto osztály bővítése


Bővítsük ki az Autó osztályát, és rögtön írjuk
bele az új változóinkat!

public class Taxi extends Auto{


private double penztarca;
private double kmdij;
// függvénytest
}
Példa – Taxi - konstruktorok

 A leszármazott nem örökli a szülő


konstruktorát.
 Van lehetőségünk a leszármazott
konstruktorának első sorában meghívni a
szülő valamelyik konstruktorát a super
kulcsszóval.
 Ha ezt nem tesszük meg, vagy ha nem is
definiálunk konstruktort, akkor is
végrehajtódik a szülő üres kostruktora
(ha van ilyen), mégpedig minden
gyermekbeli inicializációs blokk előtt.
Példa – Taxi - konstruktor

public Taxi(String tipus, double fogyasztas, int


ferohely, double kmdij) {
super(tipus, fogyasztas, ferohely);
this.kmdij=kmdij;
this.penztarca = 0;
}
Elfedés, felülírás

 Nyilván néhány változónak és metódusnak más


szerepet szánunk az új, származtatott osztályban.
 Ilyenkor felülírhatjuk, elfedhetjük a szülő azonos
szignatúrájú metódusait (egyébként egyszerű
túlterhelés lenne).
 Taxi esetén másképp számoljuk a költséget, hiszen
hozzájön még a fuvarozó kilométerdíja. Egyszerűen
írjunk új eljárásokat azonos névvel, de az új funkcióval!
 Itt is hivatkozhatunk a szülő metódusára (ha az már
egy új fv miatt el lenne fedve) a super kulcsszóval.
 A toString() függvényünket is úgy módosítsuk, hogy az
már kiírja a fuvarozó pénztárcájának tartalmát is!
Példa – Taxi

 Írjuk meg a Taxi osztályt!


 A költség számításánál vegyük figyelembe
a kilométerdíjat!
 A halad függvényt hagyjuk meg, mellé
hozzunk létre egy fuvaroz függvényt, ahol
adjuk hozzá a taxis pénztárcájához a
kilométerdíjból beszedett összeget is.
 A toString() metódus írja ki egyrészt az
Autó adatait, de tegye hozzá a taxis
pénztárcájának tartalmát is.
public double koltseg(double km){
return super.koltseg(km)+kmdij*km;
}

public void tankol(int l){


benzin+=l;
penztarca-=l*benzinar;
}

public String toString(){


return super.toString()+", a fuvarozo penze:
"+penztarca;
}
 A halad(int km) függvényt ne írjuk felül, mert
két fuvar közt egyszerű autóként halad a
taxis:
public double fuvar(double km){
if(halad(km)==km){ //a halad(int km)-t nem irtuk felul.
penztarca+=koltseg(km);
return km;
}
else return 0;
}
 Költség/fő (ha többen taxizunk, olcsóbb)
public double koltseg_per_fo(double km, int fo){
if(fo>ferohely+1){
System.out.println("Tobb utas, mint ferohely, ha
rendor jon, nagyon draga lesz!");
return 0;
}
else return koltseg(km)/fo;
}
Kész a Taxi osztály

De még nem működhet teljesen:
 Az Autó tagváltozóinak mindig private a módosítójuk, változtassuk
meg protectedre, hogy tudjuk őket használni!
 Hozzunk létre egy futtató osztályt main()-nel!
public class runAuto {
public static void main(String[] args){
Auto lada = new Auto("Lada", 10, 5);
Taxi daewoo = new Taxi("Daewoo", 7, 5, 200);
lada.tankol(40);
lada.halad(15); // Megtettunk 15.0km utat!
System.out.println(lada.toString()); // Lada, benzin: 38.5, km: 15.0
daewoo.tankol(30);
daewoo.halad(40); // Megtettunk 40.0km utat!
System.out.println(daewoo.koltseg_per_fo(15, 4)); // 815.625
daewoo.fuvar(200);
System.out.println(daewoo.toString());
// Daewoo, benzin: 13.2, km: 240.0, a fuvarozo penze: 36000.0
Ízelítő a következő óra
anyagából

 Polimorfizmus:

Auto tata = new Taxi("Tata (indiai automarka)", 9, 4, 250);


// létrehoztunk egy autót, ami egyébként egy taxi.
tata.tankol(18); // Taxival vettunk 18.0l benzint!
// tata.fuvar(100); // helytelen!
tata.halad(100); // Megtettunk 100.0km utat!
System.out.println(tata.toString());
// Tata (indiai automarka), benzin: 9.0, km: 100.0, a
fuvarozo penze: -4500.0
Véglegesítés

Hozzuk létre a Busz osztályt a Taxi osztálybol!

A buszon egy vonaljeggyel lehet utazni, szintén
van kilométerdíj, amit a sofőr kap.

A költség marad ugyanúgy, ahogy a taxinál
volt, ellenben a fuvar esetében az üzemeltető
cég pénztárcáját tekintsük, azaz a jegyárból
vontjuk ki a buszvezető díját is!

Az osztály legyen végleges, azaz már ne
lehessen szülő (final)

Az alábbi osztályokat valósítsuk meg:
 public Busz(String tipus, double fogyasztas, int
ferohely, double kmdij)
 public double fuvar(double km)
 public double fuvar(double km, int fo)
 public double Haszon(double km, int fo)
 public double koltseg_per_fo(double km, int fo)
Busz megvalósítás
public final class Busz extends Taxi {
private int jegyar = 230;

/**
* Busz konstruktora
* @param tipus A busz márkája
* @param fogyasztas //A busz fogyasztása
* @param ferohely // Férőhelyek száma
* @param kmdij //A buszvezető bére kilométerenként
*/
public Busz(String tipus, double fogyasztas, int ferohely,
double kmdij){
super(tipus,fogyasztas, ferohely, kmdij);
}
Busz megvalósítás

/**
* A fuvar ára egy vonaljegy. Most csak egy embert viszunk
* csak hogy felul tudjuk irni a Taxi fuggvenyet
*/
public double fuvar(double km){
if(halad(km)==km){ //a halad(int km)-t nem irtuk felul.
penztarca+=jegyar – km_dij*km;
return km;
}
else return 0;
}
Busz megvalósítás
/**
* Fuvar több főre.
* @param km Megtett út
* @param fo Utasok száma
* @return Megtett kilométerek száma
*/
public double fuvar(double km, int fo){
if(halad(km)==km){
penztarca+=fo*jegyar - km*kmdij;
return km;
}
else return 0;
}
Busz megvalósítása

/**
* A fuvarozó cég összköltsége. Tegyük fel, hogy
* az utasok végig utazták az utat.
* @param km A megtett kilométerek száma
* @param fo Utasok száma
* @return Költség forintban
*/
public double Haszon(double km, int fo){
return fo*jegyar - koltseg(km);
}
/**
* Akárhányan is utazunk akármennyit, csak egy
vonaljegyet veszünk.
*/
public double koltseg_per_fo(double km, int fo){
return jegyar;
}
Általánosítás


A specializálással ellentétes fejlesztés az
általánosítás.

Tegyük fel, hogy létre akarok hozni egy kerékpár
típust. Szintén lenne néhány közös jellemzője az
autóval.

Hozzunk létre egy jármű osztályt, de úgy, hogy azt ne
lehessen példányosítani, azaz legyen abstract!

Ilyenkor amelyik függvényt abstract jelzővel illetjük,
azt az utódnak muszáj felülírnia. Ez esetben a halad(),
illetve a költség() metódus lehet ilyen.

Az autóból természetesen át kell tenni néhány
változót, azokat, amik a kerékpárral, illetve
általánosságban egy járművel egyeznek!

Valósítsuk meg a járművet!
public abstract class Jarmu {
protected String tipus;
protected double km_ora;
protected int ferohely;

// Haladást megvalósító metódus, absztrakt


public abstract double halad(double km);

// Költséget kiszámoló metódus, absztrakt


public abstract double koltseg(double km);

// Egy megvalósított metódus, kiírja a nevét és a kmórát.


public String toString(){
return this.tipus+ ", " + km_ora + " km";
}
}
Kerékpár megvalósítása

 Írjuk meg a kerékpár osztályát!


 A költség legyen 0! (ezért is szeretjük a
kerékpárt) 
 A haladást csak a kilométeróra
növekedése kövesse!
 A toString() a típust és a kilométerórát írja
ki!
public final class Kerekpar extends Jarmu {
public Kerekpar( String tipus){ // Egy kerékpár
this.tipus=tipus;
this.km_ora=0;
this.ferohely=1;
}

public double halad(double km) { // A halad fv.


this.km_ora+=km;
return 0;
}

public double koltseg(double km) { // Adott utra adott koltseg.


return 0;
}
}
Vége! (majdnem)

A feladatok megoldásai megtekinthetők a
digitus../stuat/progny/ mappában.

Házi feladat:
 Hozzunk létre egy osztályhierarchiát, melyben
ingatlanokat reprezentálunk.
 Legyen egy absztrakt Ingatlan osztály, ahol az
ingatlan területe, címe és bérleti díja van, továbbá
egy metódust, ami az éves költségeket számolja ki.
 Írjunk egy Lakás osztályt, ahol a lakók számát is
tároljuk, ők a lakásért fizetnek adót, illetve rezsit.
 Írjunk egy Kollégium osztályt, mely a Lakásból
öröklődik, számoljunk az állami támogatással és
számoljuk ki az egy főre eső költségeket is.
 Végül valósítsunk meg egy Iroda osztályt is, ahol
tároljuk a cég nevét, a költségek számításánál pedig
figyelembe vesszük az adót is.
 Összes osztálynál legyen aktuális String toString
osztály!

You might also like