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 Osoba Ucet zakaznik: Osoba 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 1..4 celek čá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. Krizek 1 1 celek část Bod (stred) 11
public class Krizek { private Bod stred; private int delka = 3; Poznámky 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;
public int getdelka() { return delka; public void setstred(bod bod) { stred = bod; public void setdelka(int delka) { this.delka = delka; Poznámky 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);
public void posun(int dx, int dy) { this.smaz(); this.getstred().posunsouradnic(dx, dy); this.vykresli(); Poznámky public void posunsouradnic(int dx, int dy) { this.getstred().posunsouradnic(dx, dy);
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); Poznámky Krizek krizeka = new Krizek(new Bod(150, 200, "cervena"), 20); krizeka.vykresli();
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; Poznámky //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;
public String tostring() { return "Obdelnik levyhorni: " + getlevyhorni().tostring() + " pravydolni: " + getpravydolni().tostring(); Poznámky public int getdelkax() { return getpravydolni().getx() getlevyhorni().getx(); // return Math.abs(getPravyDolni().getX() getlevyhorni().getx());
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); Poznámky // 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);
public void posun(int dx, int dy) { this.smaz(); this.posunsouradnic(dx, dy); this.vykresli(); Poznámky public void posunsouradnic(int dx, int dy) { getlevyhorni().posunsouradnic(dx, dy); getpravydolni().posunsouradnic(dx, dy);
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 x hodnotax levyhorni y hodnotay pravydolni x hodnotax y hodnotay obdelnik 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 citac Tiskarn a 0..1 0..* celek nebo agregát agregace část 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 lastname value birthday hireday month value day value year value employee birth month value 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; public enum Chut {VYBORNA, DOBRA, SPATNA, ODPORNA public enum Barva { HERCE, PIKY, KRIZE, KULE Poznámky 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; public enum Barva {ZELENA, CERVENA, ZLUTA, SVETLE_CERVENA Poznámky Výčtový typ Barva 44
package vycet; public enum Chut {VYBORNA, DOBRA, SPATNA, ODPORNA Poznámky 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 Poznámky Jablko: barva ZELENA poradi 0 velikost 12 chut VYBORNA poradi: 0 Jablko: barva SVETLE_CERVENA poradi 3 velikost 15 chut ODPORNA poradi: 3 Poradi chuti: 3 Chut objektu j2 textove: ODPORNA Objekt j chut poradi: 1 textove: DOBRA Zadana barva: ZELENA poradi: 0 50