Upload
zane-neal
View
49
Download
2
Embed Size (px)
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
Citation preview
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!