1. Do czego służą klasy?
W programowaniu obiektowym posługujemy się obiektami.
Jak wiemy (por, jeszcze raz pkt. 4.2), obiekty charakteryzują się :
- cechami (inaczej - atrybutami lub stanami)
- operacjami, które na nich można wykonywać (inaczej - usługami, które
są obowiązane świadczyć; inaczej - poleceniami czy komunikatami, które można
im wydawać czy do nich posylac)
Obiekty w programie odzwierciedlają rzeczywiste obiekty, które mogą być konkretne (fizyczne) lub abstrakcyjne.
Na przykład, gdyby nasz program symulował ruch uliczny to musielibyśmy zapewne
odzwierciedlić w nim takie konkretne obiekty jak samochody.
Każdy z obiektów- samochodów ma jakieś cechy (atrybuty, stany) np.
- ciężar,
- wysokość,
- aktualną prędkość jazdy
oraz udostępnia jakieś usługi, wykonanie których możemy mu zlecić za pomocą odpowiednich poleceń np.
- włącz się do ruchu,
- zatrzymaj się,
- zwiększ prędkość
- skręć w lewo itp.
Gdybyśmy zatem mieli w programie dwa obiekty-samochody, to każdy z nich można by było opisać przez wartości jego atrybutów:
Samochód A (oznaczony w programie samA)
| Samochód B (oznaczony w programie samB)
| ciężar = 1000
wysokość = 1.5
aktualna prędkość = 0
| ciężar = 1000
wysokość = 1.5
aktualna prędkość = 60
|
Przypomnienie: polecenia do obiektów posyłamy za pomocą kropki
Do każdego z nich moglibyśmy też posłać komunikat (polecenie) np.
samA.włącz_się do_ruchu();
samB.zatrzymaj_się();
Skąd wiemy jakie atrybuty mają obiekty-samochody? Skąd wiemy jakie polecenia możemy do nich posyłać?
O tym decyduje definicja klasy samochodów, którą nasz program musi albo skądś pobrać albo sam dostarczyć.
Klasa - to opis takich cech grupy podobnych obiektów, które są dla
nich niezmienne (np. zestaw atrybutów i usług, ktore mogą
świadczyć)
Można by więc symbolicznie zapisać coś takiego:
Klasa Samochod
atrybuty:
ciężar wysokość akualna prędkość
usługi - operacje:
włącz_się_do_ruchu zatrzymaj_się zwiększ_prędkość skręć_w_lewo
Dopiero teraz będziemy wiedzieć co charakteryzuje każdy obiekt-samochód w
naszym programie i co możemy z każdym takim obiektem robić.
Nie należy myśleć, że np. definicja klasy samochodów jest "naturalnie" ustalona, jedyna, dana raz na zawsze.
Konkretne obiekty samochody możemy przecież w naszych programach opisywać
bardzo różnie w zależności od tego jaki problem ma do rozwiązania nasz program.
Np. w przypadku symulacji ruchu ulicznego nie będzie pewnie nas interesować
taka cecha samochodu jak kolor (zatem ten atrybut nie znajdzie się w definicji
klasy jako wspólna cecha wszystkich obiektów samochodów).
Ale być może gdyby nasz program zajmował się zagadnieniem sprzedaży samochodów,
to cecha "kolor" znalazłaby się jako istotny atrybut w definicji klasy. A
zamiast operacji: włącz się_do ruchu itp. potrzebne byłyby całkiem inne operacje na obiektach (np. sprzedaj).
W przypadku konkretnych, fizycznych obiektów to wszystko jest chyba dość
zrozumiałe. A co z obiektami abstrakcyjnymi, co to takiego, po co w ogóle
mogą być nam potrzebne?
Przypomnijmy sobie pary liczb całkowitych z poprzedniego wykładu. Niewątpliwie taka para liczb jest obiektem abstrakcyjnym (bowiem nie istnieje fizycznie).
W naszym programie odzwierciedlamy właściwości tych abstrakcyjne obiektów za pomocą definicji klasy par liczb całkowitych.
Atrybuty pary są naturalne: pierwsza liczba i druga liczba pary.
W poprzednim wykładzie wykorzystywaliśmy tylko dwie z możliwych operacji
na parze: ustalenie jej wartości (tzn. wartości pierwszego i drugiego składnika
pary) oraz pokazanie pary (wyprowadzenie na konsolę obu liczb). Mogą być
i inne operacje np.: dodawanie par, odejmowanie par. Zestaw możliwych operacji
możemy więc - taka samo jak w przypadku odzwierciedlania obiektów fizycznych
- dostosowywać do potrzeb naszych programów poprzez odpowiednią definicję
klasy.
Na przykład:
Klasa Para
atrybuty:
pierwsza_liczba_pary druga_liczba_pary
usługi - operacje:
set // ustal wartość pary add // dodaj pary substract // odejmij pary show // pokaż parę
Uwaga: to że stosujemy angielskie słowa do nazywania operacji na parach
nie ma żadnego specjalnego znaczenia; ogólnie jednak lepiej jest stosować
w programach identyfikatory w języku angielskim, gdyż w ten sposób tekst
programu wygląda bardziej naturalnie (słowa kluczowe i tak są słowami języka
angielskiego) i staje się powszechnie zrozumiały. Tę zasadę będziemy wprowadzać
w naszych przykładowych programach stopniowo, aby teksty były bardziej naturalne
i zrozumiałe dla nie znających języka angielskiego, a jednocześnie powoli
pojawiały się w nich ważne w informatyce słowa angielskie (np. add czy show).
Znowu:
ta definicja nie określa wartości cech pojedynczego obiektu. Możemy mieć
wiele obiektów par-liczb całkowitych, każdy z których ma podane atrybuty
(ale np. różne ich wartości) oraz nad każdym z których możemy wykonywac podane
operacje (set,add itd). Przy czym niekiedy możemy zdefiniować klasę Para
w taki sposób, że dopuszczalne jest odejmowanie par; a innym razem ta operacja
akurat będzie nam niepotrzebna - i wtedy definicja klasy nie będzie jej zawierać.
Zobaczmy teraz na co w ogóle może się przydać definicja klasy Para. Wyobrażmy
sobie, że w programie mamy zapisać dodawanie par liczb całkowitych. Możemy
to oczywiście zrobić, korzystając z pierwotnych typów danych:
int a1 = 1;
int a2 = 2;
int b1 = 3;
int b2 = 4;
int c1;
int c2;
c1 = a1 + b1;
c2 = a2 + b2;
Jednak mając definicję klasy Para możemy zapisać tę operację w dużo prostszy i bardziej zrozumiały sposób:
Para a = new Para(); // przypomnienie: w Javie obiekty tworzymy za pomoca wyrażenia
Para b = new Para(); // new, o którym za chwilę dowiemy się wszystkiego
a.set(1, 1);
b.set(3, 4)
Para c = a.add(b);
Zatem nie tylko opis fizycznych właściwości obiektów (które nie mają żadnych
odpowiedników w składni języka) za pomocą definicji klas może być przydatny;
również klasy obiektów abstrakcyjnych (czasem łatwiej opisywalnych za pomocą
danych typów pierwotnych) są w programowaniu bardzo przydatne.
Porównując powyższe fragmenty kodów warto zwrócić uwagę na pewną różnicę:
oto wartości zmiennych całkowitych (a1, a2, b1, b2) inicjowaliśmy przy ich
deklaracji, natomiast obiekty-pary (a i b) - tworzyliśmy, ale zamiast inicjacji
używana była operacja set.
Czy nie można by "załatwić" takiej inicjacji przy okazji tworzenia obiektu?
Ależ tak - o ile tylko definicja klasy to przewiduje.
Każda klasa może zdefiniować specjalną operację inicjacji obiektu, której można użyć "w trakcie" jego tworzenia.
Wyobraźmy sobie, że operacja taka zdefiniowana jest w klasie Para, a jej
użycie polega na podaniu w wyrażeniu new po napisie Para - w nawiasach okrągłych argumentów,
których wartości zostaną przypisane składnikom pary - nowotworzonego obiektu.
Zadanie dodania dwóch par (1,2) i (3,4) można by wtedy zapisać jeszcze prościej:
Para a = new Para(1,2);
Para b = new Para(3,4);
Para c = a.add(b);
Podkreślmy: to, że akurat można użyć takiego zapisu - zależy od definicji klasy Para.
Zatem:
Definicja klasy określa:
- zestaw cech (atrybutów) obiektów klasy,
- zestaw operacji, które można wykonywac na obiektach klasy
- specjalne operacje, które pozwalają na inicjowanie obiektów przy ich tworzeniu.
W wielu językach obiektowych (w tym w Javie):
- wspólne cechy (atrybuty) obiektów nazywają się polami klasy
- operacje (polecenia) - nazywają się metodami,
- specjalne operacje inicjacji - nazywają się konstruktorami
Definicja klasy stanowi zatem definicję:
- pól
- metod
- i konstruktorów
Klasę winniśmy traktować jako swoisty wzorzec, szablon opisujący powstawanie
obiektów (konstruktory), ich cechy (pola) oraz sposób komunikowania się z
obiektami (metody).
W Javie do definiowania klas używa się słowa kluczowego class. Samą
definicję umieszcza się w następujących po nim nawiasach klamrowych. Kod
definicji (pomiędzy nawiasami klamrowymi) nazywa się ciałem klasy.
[ public ] class NazwaKlasy {
// definicje pól
// definicje konstruktorów
// definicje metod
}
gdzie:
- słowo kluczowe public jest nieobowiązkowe (dlatego w nawiasach kwadratowych)
i określa dostępność klasy dla innych programów (klasa zdefiniowana ze słowem
public jest dostępna zewsząd)
- nazwa klasy musi spełniać ograniczenia dotyczące identyfikatorów i (zgodnie
z konwencjami nazewniczymi) powinna zaczynać się od dużej litery i być pisana
w notacji węgierskiej
Przykłady "szablonów" definicji klas:
public class Para { / definicja klasy par liczb całkowitych
// ciało klasy
}
public class Car {
// ciało klasy
}
class TestPara {
// ciało klasy
}
Pola i metody klasy nazywają się składowymi klasy.
Składowe klasy = pola + metody
|