az oop alapjai

41
AZ OOP ALAPJAI

Upload: zane-neal

Post on 02-Jan-2016

49 views

Category:

Documents


2 download

DESCRIPTION

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. - PowerPoint PPT Presentation

TRANSCRIPT

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ó - Konstruktorpublic 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:

• 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

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áspublic 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!