Podstawy programowania obiektowego Technologie internetowe Wykład 6
Program wykładu Pojęcie interfejsu i implementacji Hermetyzacja Pakiety w Javie Składowe statyczne Kompozycja - korzystanie z gotowych klas
Obiekt jako serwer usług połóż liczbę: push(int):void STOS (LIFO/LIFO) usuń liczbę : pop():void odczytaj ostatnią liczbę: top():int czy jesteś pusty: empty():boolean zbiór usług, które zapewnia obiekt Interfejs cały kod zapewniający działanie interfejsu Implementacja 2 role dla programisty: producent (pisze nowe klasy) konsument (korzysta z napisanych klas)
Interfejs class Stos { Stos(); Stos(int rozmiar); boolean empty(); void push(int liczba); void pop(); int top(); interfejs nie powinien zmieniać się interfejs jest publiczny
Implementacja/Implementacje jeśli interfejs jest obietnicą, to implementacja jest jej spełnieniem/realizacją może być więcej niż 1 (patrz poprzedni wykład) klientowi jest (prawie) obojętne, jakiej używa prawie: inne charakterystyki niż funkcjonalność (ArrayList, LinkedList) implementacja powinna być ukryta przed klientem, bo może się zmieniać implementacja jest prywatna
Hermetyzacja (encapsulation) hermetyzacja jest sposobem na wymuszenie podziału klasy na interfejs i implementacje (interfejs publiczny, implementacja prywatna) jej konsekwentne używania pomaga uniknąć kłopotów w przyszłości inne wyjaśnienia (np. prywatne pola z hasłem) przeważnie można ją ominąć, ale zwykle nie warto
class Stos { private int[] tab; private int wierzch; public Stos(int rozmiar) { tab=new int[rozmiar]; wierzch=-1; public Stos() { tab=new int[100]; wierzch=-1; Hermetyzacja public boolean empty() { return (wierzch==-1); public void push(int liczba) { tab[++wierzch]=liczba; public void pop() { -- wierzch; public int top() { return tab[wierzch]; Interfejs Stos +Stos() +Stos(int) +empty(): boolean +push(int): void +pop(): void +top(int) - tab: int[] - wierzch: int Implementacja
Hermetyzacja w praktyce Stos s = new Stos(100); s.push(20); s.pop(); System.out.println(s.wierzch); s.tab[0]=5; z interfejsu może korzystać cały kod w programie z implementacji może korzystać tylko kod klasy hermetyzacja w Javie (C++, C#) jest na poziomie klasy: class Stos { private int[] tab[], wierzch=-1; public Stos(Stos s) { this.tab=new tab[s.tab.legth]; for(int i=0;i<tab.length;++i) this.tab[i]=s.tab[i];
class Punkt { private int x, y; Metody dostępowe (accessors) zwykle metody i konstruktory są publiczne zwykle pola są prywatne metody dostępowe umożliwiają odczyt i zapis pól (prywatnych): zmienne tylko odczytu (read-only), tylko do zapisu (write-only) mogą robić coś więcej: kontrola dostępu, dziennik dostępu, kontrola poprawności public Punkt(int xx, int yy) { x=xx; y=yy; public void setx(int xx) { (if (xx>=0) x=xx; public int getx() { return x; public int gety() { return y;
Pakiety w Javie czasami chcemy mieć kilka klas o tej samej nazwie naraz (2 implementacje stosu) i ogólnie uporządkować klasy hierarchicznie Java oferuje hierarchiczne biblioteki pakiety mają one zwykle odzwierciedlenie w katalogach (lub plikach JAR) pełne nazwy klasy uwzględniają też nazwę pakietu: java.lang.string, java.util.arraylist tablice.stos, listy.stos
Pliki źrodłowego w Javie plik 'Stos.java' w katalogu '$CLASSPATH/listy/' 1 package listy; import java.util.arraylist; import java.lang.* 2 pełna nazwa klasy: 'listy.stos' zmienna środowiskowa $CLASSPATH (CLASSPATH=C:\Moje-klasy\; C:\Biblioteki.jar) 'package' określa pakiet klasy pakiet domyślny (default) public class Stos { class Element { 3 'import' służy tylko ułatwieniu użycia w 1 pliku 1 klasa (publiczna) hermetyzacja na poziomie pakietu klasy publiczne klasy pakietowe składowe pakietowe po skompilowaniu 'Stos.class' w katalogu '$CLASSPATH/listy/'!!!
Dostęp pakietowy jeśli nie piszemy 'public' ani 'private' dostęp pakietowy tylko składowe publiczne publicznych klas są dostępne z innych pakietów 'import' szybka zmiana implementacji (debug/release) //pakiet domyślny: plik 'Program.java' w katalogu '$CLASSPATH' //import tablice.stos; import listy.stos; public static class Program { public static vois main(string[] args) { Stos s=new Stos(); Element e=new Element();
Składowe statyczne Punkt p1=new Punkt(0,0), p2=new Punkt(1,1), p3=new Punkt(2,2); p1 x: 0 y: 0 p3 p2 x: 0 y: 0 x: 0 y: 0 x, y: składowe instancyjne (obiektowe) ile obiektów, tyle zmiennych (pól) 'x' i 'y' są też zmienne, które istnieją tylko w 1 kopii, niezależnie ile obiektów powstanie zmienne statyczne umieszczone są w pamięci klasy pamięci statycznej class Punkt { private int x, y; private static int a=-1; +Punkt(int, int) +getx(): int +setx(int):void +gety(): int - x: int - y: int -a: -1
Licznik obiektów class Punkt { private int x, y; private static int licznik=0; public Punkt(int xx, int yy) { x=xx; y=yy; ++ licznik; public Punkt() { x=0; y=0; ++ licznik; Punkt p1=new Punkt(0,0), p2=new Punkt(1,1), p3=new Punkt(2,2); System.out.println(Punkt.licznik); ==> 3
Funkcje statyczne tyle, że zmienna licznik jest prywatne (powinna być) można napisać metodę dostępową (obiekt ma dostęp do zmiennych statycznych swojej klasy): class Punkt { private static int licznik=0; public int ile() { return licznik; ale żeby ją wywołać, trzeba mieć obiekt!!! (p1.ile();) funkcje statyczne: wywoływane z klasy (na rzecz klasy) class Punkt { private static int licznik=0; public static int ile() { return licznik; x=0; wywoływanie: System.out.println(Punkt.ile()); ograniczenia funkcji statycznych: nie mają zmiennej 'this' nie mogą korzystać ze składowych instancyjnych
Kompozycja technika konstruowania nowych klas z wykorzystaniem klas już istniejących opisuje relację między 2 klasami: jest zbudowana z i jest elementem bardzo szeroko stosowana przechodnia Punkt Linia Procesor Komputer Gałąź Drzewo Las
Kompozycja class Punkt { class Linia { private Punkt p1, p2; public Punkt(Punkt a, Punkt b) { p1 = a; p2 = b; Punkt u = new Punkt(0, 0), v = new Punkt (1, 1); Linia l1 = new Linia(u, v), l2 = new Linia(u, v);
Inne realizacje kompozycja class Ksiazka { class Biblioteka { private Ksiazka[] ksiazki = new Ksiazki[100]; private int licznik = 0; private ArrayList<Ksiazka> ksiazki = new ArrayList<Ksiazki>; public void dodajksiazke(ksiazka k) { ksiazki[licznik++] = k; agregacja vs prawdziwa kompozycja
Metody w kompozycji class Punkt { private int x, y; public void przesun(int dx, int dy) { x += dx; y += dy; class Linia { private Punkt p1, p2; public void przesun(int dx, int dy) { p1.x += dx; p1.y += dy; p2.x += dx; p2.y += dy;
Metody w kompozycji class Punkt { private int x, y; public void przesun(int dx, int dy) { x += dx; y += dy; class Linia { private Punkt p1, p2; public void przesun(int dx, int dy) { p1.przesun(dx, dy); p2.przesun(dx, dy); LEPIEJ!!!
Metody w kompozycji class Towar { public int wartosc() { class Magazyn { private Towar[] towary; public int wartosc() { int wynik=0; for (Towar t: towary) if (t!= null) wynik += t.wartosc(); return wynik + 100000;
Tworzenie komponentów class Punkt { class Linia { private Punkt p1, p2; public Punkt(Punkt a, Punkt b) { p1 = a; p2 = b; Punkt u = new Punkt(0, 0), v = new Punkt (1, 1); Linia l1 = new Linia(u, v), l2 = new Linia(u, v); l1.przesun(2,2); System.out.println(l2.getP1().getX()); ==> 2!!! System.out.println(l2.getP1().getY()); ==> 2!!!
Tworzenie komponentów class Punkt { class Linia { private Punkt p1, p2; l1 p1 p2 x:0 2 y:0 2 u public Punkt(Punkt a, Punkt b) { p1 = a; p2 = b; l2 p1 p2 x:1 3 y:1 3 v Punkt u = new Punkt(0, 0), v = new Punkt (1, 1); Linia l1 = new Linia(u, v), l2 = new Linia(u, v); l1.przesun(2,2); System.out.println(l2.getP1().getX()); ==> 2!!! System.out.println(l2.getP1().getY()); ==> 2!!!
Tworzenie komponentów v class Punkt { class Linia { u x: 0 y: 0 x:0 2 y:0 2 x: 1 y: 1 private Punkt p1, p2; public Punkt(Punkt a, Punkt b) { p1 = new Punkt(a.getX(),a.getY()); l1 p2 = new Punkt(b); l2 p1 p2 p1 p2 x:1 3 y:1 3 x: 0 y: 0 x: 1 y: 1 Punkt u = new Punkt(0, 0), v = new Punkt (1, 1); Linia l1 = new Linia(u, v), l2 = new Linia(u, v); l1.przesun(2,2); System.out.println(l2.getP1().getX()); ==> 0!!! System.out.println(l2.getP1().getY()); ==> 0!!!