OOPR_04
1
Přehled probírané látky • asociace (relace) mezi třídami – popis množiny spojení mezi objekty
• skládání objektů - upřesněný typ asociace, vazba mezi objekty – kompozice objektů (velmi pevná vazba mezi objekty) – agregace objektů (volná vazba mezi objekty)
• grafické složené objekty – křížek, obdélník • výčtové typy (enumeration)
2
Asociace mezi třídami • Asociace – relace, vazba mezi třídami. • Jednosměrná, obousměrná. • Řešení pomocí datových atributů, které odkazují na odpovídající třídu.
3
Asociace mezi třídami Ucet zakaznik: Osoba
Ucet
Osoba
Osoba
zakaznik: Osoba mujUcet: Ucet
public class Ucet { private Osoba zakaznik; . . . } public class Osoba { private Ucet mujUcet; . . . } 4
Skládání vazba mezi objekty • Obecný vztah mezi třídami se nazývají asociace. – asociace mezi třídami Ucet a Zakaznik
• Skládání – upřesnění asociace. • Skládání je prostředek k organizování jevů a konceptů ve smyslu komponentů jiných jevů a konceptů. • Existuje několik způsobů skládání jevů do složených jevů. Kompozice, agregace, lokalizace. 5
Asociace – vztah mezi třídami • asociace (a to jednostranná, nebo oboustranná). • U jednostranné asociace zná jen jedna třída rozhraní druhé třídy, u oboustranné zná každá třída rozhraní svého partnera. • Průchodnost, směrování (směr šipky) navigability.
6
Skládání objektů •
•
kompozice je typem velmi těsné vazby mezi objekty – vyskytuje se např. mezi stromem a jeho listy, mezi autem a jeho jednotlivými součástmi (kola, karoserie, volant, motor ... ), dřevěný panáček (hlava, krk, ruce, trup, nohy). agregace (referenční kompozice) je volnou vazbou mezi objekty – vyskytuje se např. mezi počítačem a jeho periferními zařízeními, rezervace a odkazy na hotel, pokoj a hosta. 7
Skládání objektů • používané termíny: – celek nebo složený objekt – části (složeného objektu).
8
Sémantika kompozice
Myš
Tlačítka 1
celek
1..4
část kompozice
• Kompozice je silnější formou skládání objektů. • V kompozici nemohou části existovat mimo celek. • V kompozici každá část patří pouze jednomu celku.
9
Kompozice shrnutí • Části patří jen a pouze jednomu celku (kompozici). • Celek nese výhradní odpovědnost za použití všech svých částí – znamená to zodpovědnost za jejich tvorbu a zničení. • Za předpokladu, že odpovědnost za části přejde na jiný objekt, může celek tyto části uvolnit. • Je-li celek zničen, musí zničit rovněž všechny svoje součásti, nebo převést odpovědnost za ně na nějaký další objekt. 10
Příklad kompozice – objekt Křížek • Třída Krizek má datový atribut typu Bod – označuje střed křížku a primitivní typ délka – délka ramene křížku.
1
1
Krizek celek
Bod (stred)
část
11
public class Krizek { private Bod stred; private int delka = 3; public Krizek() { stred = new Bod(); } public Krizek(Bod bod, int delka) { //stred = bod; - normalni prirazeni // pouziti kopirivaciho konstruktoru tridy Bod stred = new Bod(bod); this.delka = delka; } // kopirovaci konstruktor public Krizek(Krizek kr) { stred = new Bod(kr.getStred()); delka = kr.getDelka(); } //modifikacni a pristupove metody public Bod getStred() { return stred; }
Poznámky
public int getDelka() { return delka; } public void setStred(Bod bod) { stred = bod; } public void setDelka(int delka) { this.delka = delka; } public void vykresli() { for(int i = 0; i < getDelka() * 2 + 1; i++){ //vodorovne getStred().vykresli( - getDelka() + i, 0); //svisle getStred().vykresli(0, - getDelka() + i); getStred().pauza(20); } } public void smaz() { for(int i = 0; i < getDelka() * 2 + 1; i++){ //vodorovne getStred().smaz( - getDelka() + i, 0); //svisle getStred().smaz(0, - getDelka() + i); getStred().pauza(20); } }
Poznámky
public void posun(int dx, int dy) { this.smaz(); this.getStred().posunSouradnic(dx, dy); this.vykresli(); } public void posunSouradnic(int dx, int dy) { this.getStred().posunSouradnic(dx, dy); }
Poznámky
public class KrizekTest { public static void main(String[] args) { Bod bod = new Bod(100, 120, Color.blue); Krizek krizek = new Krizek(bod, 40); krizek.vykresli(); bod.pauza(1500); krizek.posun(200, 100); Krizek krizekA = new Krizek(new Bod(150, 200, "cervena"), 20); krizekA.vykresli(); } }
Poznámky
Příklad kompozice • Obdelnik je složen ze objektů třídy Bod – případ pevné vazby, Obdelnik = celek, Body = části. • Objekty částí (instance třídy Bod) jsou deklarovány přímo v konstruktoru. • Pokud jsou předávány odkazy objektů třídy Bod do konstruktoru třídy Obdelnik, je doporučeno použít kopírovací konstruktor.
16
public class Obdelnik { private Bod levyHorni; private Bod pravyDolni; //konstruktory public Obdelnik() { levyHorni = new Bod(); pravyDolni = new Bod(); } public Obdelnik(Bod a, Bod b) { //levyHorni = a; //pravyDolni = b; levyHorni = new Bod(a); pravyDolni = new Bod(b); } public Obdelnik(Obdelnik ob) { levyHorni = new Bod(ob.getLevyHorni()); pravyDolni = new Bod(ob.getPravyDolni()); } // pristupove metody public Bod getLevyHorni() { return levyHorni; }
Poznámky
public String toString() { return "Obdelnik levyHorni: " + getLevyHorni().toString() + " pravyDolni: " + getPravyDolni().toString(); } public int getDelkaX() { return getPravyDolni().getX() – getLevyHorni().getX(); // return Math.abs(getPravyDolni().getX() – getLevyHorni().getX()); }
Poznámky
public void vykresli() { // kreslí vodorovné strany obdelníka for(int i = 0; i <= getDelkaX(); i++) { getLevyHorni().vykresli(i, 0); getPravyDolni().vykresli(-i, 0); getPravyDolni().pauza(20); } // kreslí svislé strany obdelníka for(int i = 0; i <= getDelkaY(); i++) { getLevyHorni().vykresli(0, i); getPravyDolni().vykresli(0, -i); getLevyHorni().pauza(20); } } public void smaz() { // maže vodorovné strany obdelníka for(int i = 0; i <= getDelkaX(); i++) { getLevyHorni().smaz(i, 0); getPravyDolni().smaz(-i, 0); getPravyDolni().pauza(20); }
Poznámky
public void posun(int dx, int dy) { this.smaz(); this.posunSouradnic(dx, dy); this.vykresli(); } public void posunSouradnic(int dx, int dy) { getLevyHorni().posunSouradnic(dx, dy); getPravyDolni().posunSouradnic(dx, dy); } }
Poznámky
Objekt celek, objekt(y) části • V objektu celek pracujeme s objekty částí, nezasahujeme přímo do vnitřních atributů objektů části – správný postup: public void posun(int dx, int dy) { levyHorni.posun(dx,dy); pravyDolni.posun(dx,dy); } špatný postup!!! public void posun(int dx, int dy) { levyHorni.setX(levyHorni.getX() + dx); levyHorni.y = levyHorni.y + dy; pravyDolni.setY(pravyDolni.getX() + dx); pravyDolni.y = pravyDolni.y + dy; }
21
Grafické znázornění vazeb mezi objekty Obdelnik a Bod
levyHorni
x
hodnotaX
y
hodnotaY
pravyDolni
obdelnik
x
hodnotaX
y
hodnotaY
bodA bodB
22
Třída Obdelnik_A • Přímo při deklaraci datových atributů jsou vytvářeny jejich instance (objekty) • Konstruktor bez parametrů je prázdný
23
public class Obdelnik_A { private Bod levyHorni = new Bod(10, 20); private Bod pravyDolni = new Bod(); // konstruktory tridy Obdelnik public Obdelnik_A() { // levyHorni = new Bod(); pravyDolni= new Bod(); // je jiz provedeno drive } public Obdelnik_A(Bod a, Bod b) { // objekty jsou jiz vytvorene, pouze kopirujeme datove atributy levyHorni.setBod(a); pravyDolni.setBod(b); } public void posun(int dx1, int dy1, int dx2, int dy2) { levyHorni.posun(dx1,dy1); pravyDolni.posun(dx2,dy2); } public String toString() { String tx= String.format("\n%s %s %s %s", "Obdelnik levyHorni: ", levyHorni.toString(), " pravyDolni: ", pravyDolni.toString()); return tx; } public void tisk() { System.out.println(this.toString()); }
Poznámky Třída Obdelnik_A
24
UML diagram kompozice
25
Sémantika agregace • Agregace je relací typu celek / část (skládající se z mnoha dílčích částí). • V tomto typu relace používá jeden objekt (celek) služby dalšího objektu (části). • Celek: – bývá dominantní v relaci, – řídí chod relace.
• Část: – poskytuje služby, – reaguje na požadavky celku (je pasivní). 26
Sémantika agregace
P o c ita c
T is k a rn a 0 ..1
celek nebo agregát
0 ..*
část agregace
• k Počítači může být připojeno více tiskáren, ale i žádná • Tiskárna může být připojena max. k jednomu počítači, nebo žádnému počítači • danou Tiskárnu může postupně používat více Počítačů • Tiskárna je v podstatě na Počítači nezávislá
27
Shrnutí agregace • Celek (agregát) bývá závislý na částech, ale může existovat nezávisle na nich (občas také existuje). • Části mohou existovat nezávisle na celku. • Chybí-li některé části, je celek v jistém smyslu neúplný. • Části mohou být sdíleny více celky.
28
Příklad kompozice (agregace) objektů tříd Zaměstnanec a Datum • Třída Zaměstnanec přebírá již vytvořené objekty třídy Datum ve svém konstruktoru
Date -day -month -year
2
1
Employee -firstName -secondName
29
public class Date { private int month; // 1-12 private int day; // 1-31 based on month private int year; // any year
Poznámky
// constructor: call checkMonth to confirm proper value for month; // call checkDay to confirm proper value for day public Date( int theMonth, int theDay, int theYear ) { month = checkMonth( theMonth ); // validate month year = theYear; // could validate year day = checkDay( theDay ); // validate day System.out.printf( "Date object constructor for date %s\n", this ); } // end Date constructor // utility method to confirm proper month value private int checkMonth( int testMonth ) { if ( testMonth > 0 && testMonth <= 12 ) // validate month return testMonth; else // month is invalid { System.out.printf( "Invalid month (%d) set to 1.", testMonth ); return 1; // maintain object in consistent state } // end else } // end method checkMonth
30
// utility method to confirm proper day value based on month and year private int checkDay( int testDay ) { int daysPerMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Poznámky
// check if day in range for month if ( testDay > 0 && testDay <= daysPerMonth[ month ] ) return testDay; // check for leap year if ( month == 2 && testDay == 29 && ( year % 400 == 0 || ( year % 4 == 0 && year % 100 != 0 ) ) ) return testDay; System.out.printf( "Invalid day (%d) set to 1.", testDay ); return 1; // maintain object in consistent state } // end method checkDay // return a String of the form month/day/year public String toString() { return String.format( "%d/%d/%d", month, day, year ); } // end method toString
31
// copy constructor public Date(Date date) { month = checkMonth( date.getMonth( )); // validate month year = date.getYear( ); // could validate year day = checkDay( date,getDay( ) ); // validate day
Poznámky
System.out.printf( “Copy constructor for date %s\n", this ); } // end Copy constructor public int getDay() { return day; } public int getMonth() { return month; } public int getYear() { return year; }
} // end class Date
32
public class Employee { private String firstName; private String lastName; private Date birthDate; private Date hireDate;
Poznámky
// constructor to initialize name, birth date and hire date public Employee( String first, String last, Date dateOfBirth, Date dateOfHire ) { firstName = first; lastName = last; birthDate = new Date(dateOfBirth); //kompozice hireDate = new Date(dateOfHire); //kompozice // birthDate = dateOfBirth; // agregace // hireDate = dateOfHire; // agregace } // end Employee constructor // convert Employee to String format public String toString() { return String.format( "%s, %s Hired: %s Birthday: %s", lastName, firstName, hireDate, birthDate ); } // end method toEmployeeString } // end class Employee
33
public class EmployeeTest { public static void main( String args[] ) { Date birth = new Date( 7, 24, 1949 ); Date hire = new Date( 3, 12, 1988 ); Employee employee = new Employee( "Bob", "Blue", birth, hire );
Poznámky
System.out.println( employee ); Employee e1 = new Employee(“John”, “Frost”, new Date(12, 4, 1981), new Date(11, 18, 1950)); System.out.println(e1); } // end main } // end class EmployeeTest
34
Grafické znázornění vazeb mezi objekty
firstName
value
month value
lastName
value
day
value
year
value
birthDay hireDay
month value
employee
birth
day
value
year
value
hire
35
Rozdíl mezi prázdným řetězcem a null • jsou dvě různé věci: • prázdný řetězec je ale platný řetězec • dotaz pomocí if (s == “”) příkaz • žádný řetězec (proměnná nikam neukazuje – ukazuje na null) • dotaz pomocí if (s == null) příkaz
36
Výčtové typy • Výčtový typ zavedl Pascal, aby umožnil typovou kontrolu proměnných a konstant, které mohly nabývat pouze omezeného počtu hodnot (dny v týdnu, světové strany atd.) • Jejich všechny možné hodnoty je možné vyjádřit výčtem. • Java 5.0 zavádí výčtové typy jako nový druh třídy, která je oproti uživatelově definici doplněna překladačem o další atributy a metody. 37
Nejjednodušší definice příklad s náhodnými čísly deklarace přímo uvnitř třídy private enum Status { CONTINUE, WON, LOST }; Status gameStatus; //“object“ declaration // possible values CONTINUE, WON, LOST gameStatus = Status.CONTINUE; while ( gameStatus == Status.CONTINUE ) gameStatus = Status.LOST;
38
package statik;
Poznámky
public enum Chut {VYBORNA, DOBRA, SPATNA, ODPORNA } public enum Barva { HERCE, PIKY, KRIZE, KULE }
Deklarace jednoduché třídy výčtového typu
public enum Hodnota { dve, tri, ctyri, pet, sest, sedm, osm, devet, deset, kluk, dama, kral, eso }
39
Činnost překladače • Překladač definuje třídu jako potomka třídy Enum (java.lang.Enum). • U výčtových typů je implicitní konstruktor soukromý a dvouparametrický (standardně veřejný a bezparametrický) – první parametr je název definované konstanty – druhý parametr je její pořadí.
• Překladač definoval statický atribut $VALUES, jenž je vektorem a obsahuje odkazy na definované výčtové typy. 40
Činnost překladače • Překladač definoval metodu values(), která vrací kopii vektoru $VALUES. • Překladač definoval metodu valueOf(String), která vrací odkaz na instanci, jejíž název převzala jako parametr.
41
Nově definované metody • public final String name() vrací název příslušné výčtové konstanty
• public final int ordinal() vrací pořadí definice konstanty. Konstanta definovaná jako první má pořadí 0, poslední n - 1
42
Výčtové typy - příklad • Deklarujeme třídu Jablko s výčtovými typy Barva a Chuť. • Výčtové typy deklarované uvnitř třídy se dají použít pouze v té třídě. • Výčtové typy deklarujeme samostatně, protože je pak můžeme používat ve více třídách (ne pouze Jablko, ale i JablkoTest).
43
package vycet;
Poznámky
public enum Barva {ZELENA, CERVENA, ZLUTA, SVETLE_CERVENA
Výčtový typ Barva }
44
package vycet;
Poznámky
public enum Chut {VYBORNA, DOBRA, SPATNA, ODPORNA
Výčtový typ Chuť }
45
public class Jablko { private Barva barva; private int velikost; private Chut chut;
Poznámky
// alternativni deklatrace uvnitr tridy //private enum Barva {ZELENA, CERVENA, ZLUTA, SVETLE_CERVENA}; //private enum Chut {VYBORNA, DOBRA, SPATNA, ODPORNA}; public Jablko(){ this(Barva.ZLUTA, 0, Chut.DOBRA); } public Jablko(Barva barva, int velikost, Chut chut){ this.barva = barva; this.velikost = velikost; this.chut = chut; } public int getVelikost(){ return velikost; } public Chut getChut(){ return chut; } public Barva getBarva(){ return barva; }
46
public String toString(){ String t = String.format("\n%s barva %s poradi %d velikost %d chut %s" + " poradi: %d", "Jablko: ",barva.name(),barva.ordinal(), getVelikost(),chut.name(), chut.ordinal()); return t; }
Poznámky
public void tisk(){ System.out.println(this.toString()); } }
47
package vycet; import javax.swing.JOptionPane; public class JablkoTest {
Poznámky
public static void main(String[] args) { Jablko j = new Jablko(); j.tisk(); Jablko j1 = new Jablko(Barva.valueOf("ZELENA"), 12, Chut.valueOf("VYBORNA")); Chut c; j1.tisk(); Jablko j2 = new Jablko(Barva.SVETLE_CERVENA, 15, Chut.ODPORNA); j2.tisk(); int k = j2.getChut().ordinal(); System.out.println("Poradi chuti: "+k); String t = j2.getChut().name(); System.out.println("Chut objektu j2 textove: "+t); c = j.getChut(); System.out.printf("Objekt j chut poradi: %d textove: %s", c.ordinal(), c.name());
48
String nazev = JOptionPane.showInputDialog("Zadejte barvu jablka:");
Poznámky
nazev = nazev.toUpperCase(); Barva b = Barva.valueOf(nazev); System.out.printf("\nZadana barva: %s poradi: %d", b.name(),b.ordinal()); } }
49
Jablko:
barva ZLUTA poradi 2 velikost 0 chut DOBRA poradi: 1
Jablko:
barva ZELENA poradi 0 velikost 12 chut VYBORNA poradi: 0
Jablko:
barva SVETLE_CERVENA poradi 3 velikost 15 chut ODPORNA poradi: 3
Poznámky
Poradi chuti: 3 Chut objektu j2 textove: ODPORNA Objekt j chut poradi: 1 textove: DOBRA Zadana barva: ZELENA poradi: 0
50