1
Podstawy programowania II
dr inż. Paweł Róg
2
Zagadnienia
■
Zagadnienia zaawansowane
Pola stałe.
Polimorfizm.
Klasy i metody abstrakcyjne.
Interfejsy.
Klasy i metody finalne.
Informacja o typie w czasie wykonania.
Magiczne metody.
3
Pola stałe
■
Pola stałe definiujemy za pomocą słowa const.
class Produkt {
protected $typ;
protected $nazwa;
const FUNTY_NA_KG = 0.45359237;
// ...
}
4
Pola stałe
■
Odwołanie do stałej z wnętrza klasy:
self::
FUNTY_NA_KG;
■
Odwołanie do stałej z zewnątrz:
Produkt::
FUNTY_NA_KG;
5
Pola stałe
■
Wartości stałego pola nie można zmienić, można
jednak nadpisać takie pole w klasie pochodnej:
class klasaA {
const STALA_LICZBA=5;
}
class klasaB extends klasaA {
const STALA_LICZBA=21;
}
print klasaA::STALA_LICZBA . '<br />';
print klasaB::STALA_LICZBA ;
6
Polimorfizm
■
Jako przykład rozpatrzmy hierarchię klas implementującą
proste obiekty „graficzne”.
■
Klasą bazową dla wszystkich obiektów będzie klasa
Figura.
■
Najważniejszą metodą w tej hierarchii klas będzie metoda
rysuj() „wyświetlająca” figurę na ekranie.
■
Pozostałe klasy (Kwadrat, Trojkat, Kolo) będą
dziedziczyć po klasie Figura i dostarczać własną
implementację metody rysuj().
Polimorfizm (wielopostaciowość) jest mechanizmem
programowania
obiektowego
polegającym
na
dynamicznym określaniu zachowania obiektu w trakcie
działania programu na podstawie jego rzeczywistego
typu.
Polimorfizm (wielopostaciowość) jest mechanizmem
programowania
obiektowego
polegającym
na
dynamicznym określaniu zachowania obiektu w trakcie
działania programu na podstawie jego rzeczywistego
typu.
7
class Figura {
public function
rysuj()
{
print "Rysuję bezkształtną
figurę...<br />";
}
}
class Kwadrat extends Figura {
public function
rysuj()
{
print "Rysuję kwadrat!<br />";
}
}
8
class Trojkat extends Figura {
public function
rysuj()
{
print "Rysuję trójkąt!<br />";
}
}
class Kolo extends Figura {
public function
rysuj()
{
print "Rysuję koło!<br />";
}
}
9
funkcja rysowanie(Figura $f) {
print "Inne operacje...<br / >";
$f->
rysuj()
;
}
for (int $i=0; $i<10; $i++) {
$losowa = rand(1,3);
switch ($losowa) {
case 1 : $figury[$i] = new Kwadrat(); break;
case 2 : $figury[$i] = new Trojkat(); break;
default: $figury[$i] = new Kolo();
}
foreach ($figury as $f) {
rysowanie($f);
}
10
Klasy abstrakcyjne
■
W poprzednim przykładzie widać bardzo wyraźnie, że nie
ma sensu tworzyć obiektu klasy Figura, gdyż wywołanie
dla niego metody rysuj() nie ma większego sensu.
Z drugiej strony, klasa Figura nadaje się bardzo dobrze
na klasę bazową dla innych, konkretnych klas figur. Fakt
ten możemy wyrazić, czyniąc klasę Figura klasą
abstrakcyjną:
abstract
class Figura {
public function rysuj() {
print "Rysuję bezkształtną
figurę...<br />";
}
}
11
Metody abstrakcyjne
■
Abstrakcyjna klasa Figura nie dostarcza
sensownej implementacji dla metody rysuj()
i dlatego naturalne będzie określenie, że metoda
ta jest abstrakcyjna. W ten sposób dajemy do
zrozumienia, że sensowna implementacja tej
metody dostarczona zostanie przez klasy
pochodne:
abstract class Figura {
abstract
public function rysuj();
}
}
12
Interfejsy
■
Możemy iść jeszcze dalej i zastrzec, że Figura
deklaruje jedynie interfejs, który musi być
zaimplementowany przez konkretne klasy figur:
interface
Figura {
public function rysuj();
}
}
class Kwadrat
implements
Figura {
public function rysuj() {
print "Rysuję kwadrat!<br />";
}
}
13
Klasy finalne
■
Jeśli chcemy, aby z danej klasy nie można było
wyprowadzać klas potomnych, należy definicję
klasy poprzedzić modyfikatorem final:
final
class Kwadrat implements Figura {
public function rysuj() {
print "Rysuję kwadrat!<br />";
}
}
14
Metody finalne
■
Jeśli chcemy, aby dana metoda nie mogła zostać
nadpisana w klasie pochodnej, należy definicję tej
metody poprzedzić modyfikatorem final:
class Kwadrat implements Figura {
final
public function rysuj() {
print "Rysuję kwadrat!<br />";
}
}
15
Powtórzenie
■
Aby zadeklarować pole stałe w klasie należy użyć
modyfikatora const.
■
Wartość stałego pola nie może być zmieniona
w czasie wykonania programu, można jednak
nadpisać stałe pole w klasie pochodnej.
■
Polimorfizm (wielopostaciowość) jest
mechanizmem programowania obiektowego
polegającym na dynamicznym określaniu
zachowania obiektu w trakcie działania programu
na podstawie jego rzeczywistego typu.
■
Jeśli chcemy, aby klasa mogła być klasą
pochodną dla innych klas, ale nie ma sensu
tworzyć obiektów tej klasy, powinna być ona klasą
abstrakcyjną (abstract).
16
Powtórzenie
■
Jeśli jakaś klasa jest na tyle wysoko w hierarchii
klas, że nie wszystkie jej metody mogą być
sensownie zaimplementowane, metody te należy
uczynić abstrakcyjnymi.
■
Interfejs (interface) deklaruje, co może być
zrobione, ale nie mówi jak. Dopiero klasa, która
implementuje (implements) interfejs dostarcza
konkretnych implementacji metod.
■
Jeśli z jakichś względów nie chcemy, aby dana
klasa mogła być klasą bazową dla innych klas,
musimy zadeklarować ja jako final.
■
Jeśli nie chcemy, aby jakaś metoda mogła być
nadpisana w klasach pochodnych, również
musimy uczynić ją
final
.
17
Informacja o typie w czasie wykonania
■
get_class()
■
get_parent_class()
■
is_subclass_of()
■
instanceof
18
get_class()
■
Aby w trakcie działania programu otrzymać typ
danego obiektu możemy wykorzystać funkcję
get_class():
$figura = new Kwadrat();
get_class
($figura);
19
get_parent_class()
■
Aby w trakcie działania programu otrzymać typ
klasy bazowej dla danego obiektu możemy
wykorzystać funkcję get_parent_class():
$kwadrat = new Kwadrat();
get_parent_class
($kwadrat);
20
is_subclass_of
■
Aby sprawdzić, czy dany obiekt jest obiektem
klasy, która jest klasą pochodną wobec innej
klasy, możemy użyć funkcji is_subcalss_of():
$kwadrat = new Kwadrat();
if (
is_subclass_of
($kwadrat, 'Figura'))
{
print 'OK';
}
21
instanceof
■
Podobne działanie do funkcji
is_subclass_of() ma operator instanceof,
z tą różnicą, że instanceof pozwala sprawdzić
również, czy dany obiekt implementuje dany
interfejs:
$kwadrat = new Kwadrat();
if ($kwadrat
instanceof
Figura) {
print 'OK';
}
22
Zastosowanie instanceof
function rysowanie ($cos) {
if ($cos
instanceof
Figura) {
$cos->rysuj();
} else {
print 'Tego czegoś nie da się
narysować...';
}
23
Magiczne metody
■
__toString()
■
__get()
■
__set()
24
__toString()
■
Magiczna metoda __toString() umożliwia
automatyczne otrzymanie tekstowej reprezentacji
obiektu:
class Kwadrat extends Figura {
// ...
public function
__toString()
{
return 'KWADRAT';
}
}
$kwadrat = new Kwadrat();
print $kwadrat;
25
__get() i __set()
class Leniwa {
protected
$_props
;
public function
__get
($nazwa) {
if (isset($this->_props[$nazwa]){
return $this->_props[$nazwa];
} else {
return false;
}
}
public function
__set
($nazwa, $wartosc) {
$this->_props[$nazwa] = $wartosc;
}
}