10.11.2010 16:59:45
Języki Automaty Obliczenia
Paradygmat programowania obiektowego
1. Cel ćwiczenia
Celem ćwiczenia jest napisanie w języku PHP programu, który będzie liczył iloczyn kartezjański
N zbiorów wczytanych z pliku. Nie znamy ilości zbiorów.
2. Wstęp
Zgodnie z paradygmatem programowania obiektowego, program jest zbiorem obiektów komuniku-
jących się między sobą w określony sposób. Każdy obiekt posiada pewien stan (dane charakteryzu-
jące obiekt) i zachowanie (metody przetwarzające dane). Zbiór obiektów posiadających identyczne
cechy tworzy klasę. Klasy mogą posiadać powiązania strukturalne między sobą.
Spośród obiektów tworzących program, wyróżniamy 3 grupy:
1. Obiekty warstwy danych.
2. Obiekty warstwy logiki.
3. Obiekty warstwy prezentacji.
2.1. Obiekty warstwy danych
Obiekty te odpowiadają strukturom danych z języka C i ich zastosowanie jest identyczne, jak
w przypadku struktur. Pomiędzy obiektami występują zwykle zależności strukturalne (związki).
Rozpatrzmy np. klasy obiektów płyta CD i utwór na płycie CD. Po polsku powiemy, że:
•
na jednej płycie CD znajduje się wiele utworów,
•
dany utwór przypisany jest do konkretnej płyty CD.
Używając języka PHP zapiszemy:
class Utwor {
//pola z danymi o utworze
/**
* @var PlytaCD
*/
$plyta;
}
class PlytaCD {
//tutaj pola z danymi o płycie
/**
* @var UtworyList
*/
$utwory;
}
Dostęp do danych charakteryzujących obiekt powinien odbywać się przy użyciu publicznych metod.
Dla klasy
Utwor
mamy:
class Utwor {
private $wykonawca;
private $czasTrwania;
private $plyta;
public function getWykonawca() {return $this->wykonawca;}
public function setWykonawca($w) {$this->wykonawca = $w;}
// pozostałe metody get i set
}
© G. Dec, 2010
1
Należy dokładnie przemyśleć potrzebę dodania innych metod niż
get
i
set
do obiektów warstwy da-
nych. Zwykle ich obecność jest błędem logicznym. Np. metoda
odtworz()
w obiekcie klasy
Utwor
wydaje się poprawna, bo jej zadaniem jest odtworzenie tego konkretnego utworu. Jednak ścieżka na
płycie CD sama się nie odtwarza, potrzebne jest urządzenie potrafiące prezentować muzykę.
2.2. Obiekty warstwy logiki
Zadaniem tych obiektów jest realizacja algorytmów przetwarzających dane modelowane przez war-
stwę danych. W przykładzie z płytą CD i utworami, można utworzyć klasę obiektów
SystemCD-
Player
, której zadaniem jest przetwarzanie danych z płyt CD:
class SystemCDPlayer {
private $plyta;
//tutaj inne pola potrzebne systemowi do pracy
public function setPlytaCD($plyta) {$this->plyta = $plyta;}
public function getPlytaCD() {return $this->plyta;}
public function play($sciezka) {. . .}
public function createMP3($sciezka) {. . .}
//tutaj pozostałe metody
}
Pomiędzy warstwą logiki i warstwą danych nie ma zależności strukturalnych. Powiemy, że
Sys-
temCDPlayer
używa płyty CD, w celu odtworzenia jej utworów. Stwierdzenie, że system jest zwią-
zany z pewną płytą CD lub utworem nie jest prawdziwe.
Obiekty warstwy logiki muszą być wyspecjalizowane w realizacji jednej funkcjonalności.
Sys-
temCDPlayer
nie potrafi obsługiwać przycisków, wyświetlacza, głośnika urządzenia. Zawiera kod,
który np. przetwarza dane z postaci zapisanej na ścieżce CD na postać akceptowalną przez obiekt
klasy
Głośnik
.
2.3. Obiekty warstwy prezentacji
Bardzo często mamy do czynienia z sytuacją, że dane po przetworzeniu przez warstwę logiki po-
winny być przedstawione w pewien sposób. Zadanie prezentacji danych wykonują specjalizowane
obiekty. Są one interfejsem pomiędzy klientem programu (użytkownikiem, innym programem),
a warstwą logiki. W przykładzie z płytą CD i utworami, można utworzyć klasę obiektów
CDPlayer
,
której zadaniem jest obsługa przycisków i wyświetlacza urządzenia. Klasa ta używa klasy
Sys-
temCDPlayer
w celu realizacji funkcji poszczególnych przycisków.
3. Przebieg ćwiczenia
Na poprzednich zajęciach napisany został program, który wczytuje dane z pliku tekstowego i zapisuje
je jako obiekt. Wykorzystamy ten program do celu wczytywania danych. Warstwę danych programu
stanowią klasy systemowe języka PHP (tablice) i nie ma potrzeby tworzyć własnych obiektów
warstwy danych.
Tworzymy prosty program konsolowy, który nie ma interfejsu użytkownika, dlatego nie będziemy
tworzyć obiektów warstwy prezentacji. Zadaniem tym zajmiemy się na kolejnych zajęciach.
Zadaniem programu jest wczytanie danych z pliku, obliczenie iloczynu kartezjańskiego i wyświe-
tlenie wyniku. Mamy więc 2 zupełnie różne zadania:
1. Wczytanie danych z pliku tekstowego i zamiana ich na odpowiednie obiekty.
2. Obliczenie iloczynu kartezjańskiego.
W celu realizacji tych zadań utworzymy 2 klasy:
OdczytDanych
i
IloczynKartezjanski
.
© G. Dec, 2010
2
3.1. Zamknij otwarte projekty w Netbeans
Uruchom program netbeans. Może się zdarzyć, że po uruchomieniu środowiska Netbeans, otwarte
zostaną projekty z innych zajęć. Zamknij je wszystkie.
Na rysunku powyżej otworzone są trzy projekty. Dla każdego projektu:
•
kliknij lewym przyciskiem myszy w nazwę projektu, żeby go podświetlić,
•
wciśnij na klawiaturze klawisz z napisem Delete lub Del,
•
w okienku Delete Project zaznacz opcję Also delete sources,
•
w okienku Delete Project kliknij przycisk z napisem Yes.
3.2. Utworzenie projektu i struktury programu.
W środowisku Netbeans otwórz projekt PHP z poprzednich zajęć. Dodaj do niego dwie klasy:
•
OdczytDanych
,
•
IloczynKartezjanski
.
3.3. Klasa odczytująca dane
1. Do klasy
OdczytDanych
dodaj dwa prywatne pola:
•
nazwaPliku
, które będzie przechowywać nazwę pliku z danymi,
•
zbiory
, które będzie przechowywać dane wczytane z pliku.
2. Dodaj publiczne metody
get
i
set
dla pól.
3. Dodaj publiczną bezparametrową metodę
odczytaj
.
© G. Dec, 2010
3
4. Przenieś do metody
odczytaj
kod z metody
main
klasy
ProgramJAO
z poprzednich zajęć.
5. Popraw linijkę otwierającą plik (ta z funkcją
fopen
), tak żeby otworzony został plik o nazwie
zapisanej w polu
nazwaPliku
klasy.
6. Popraw kod metody
odczytaj
w taki sposób, żeby dane odczytane z pliku znalazły się
w polu
zbiory
klasy.
3.3.1 Dokumentowanie kodu
W języku PHP nie ma typów, ale bardzo rzadko mamy do czynienia ze zmiennymi, których typ nie
jest znany. Dlatego opracowano system, który pozwala umieszczać informacje o typach zmiennych
w komentarzach. Z informacji tych korzysta Netbeans wyświetlając podpowiedzi.
Uzupełnij pola klasy
OdczytDanych
o informacje o ich typie:
1. Ustaw kursor tekstowy w pustej linii przed deklaracją pola
nazwaPliku
.
2. Wpisz znaki
/**
i wciśnij klawisz enter.
3. Netbeans utworzy szablon komentarza.
Uzupełnij komentarz o informacje o typie i znaczeniu pola:
/**
*
* @var string przechowuje nazwę pliku z danymi
*/
private
$nazwaPliku
;
/**
*
* @var array dane wczytane z pliku
*/
private
$zbiory
;
Podobnie jak w przypadku pól, komentarze przed metodą zawierają informację o typach parametrów
i wartości zwracanej przez metodę:
/**
* Zwraca nazwę pliku z danymi.
* @return string Zwraca nazwę pliku z danymi
*/
public function getNazwaPliku() {return
$this
->
nazwaPliku
;}
/**
* Ustawia nazwę pliku z danymi.
* @param string $nazwaPliku nazwa pliku z danymi
*/
public function setNazwaPliku(
$nazwaPliku
) {
$this
->
nazwaPliku
=
$nazwaPliku
;
}
© G. Dec, 2010
4
3.4. Klasa obliczająca iloczyn kartezjański
1. Do klasy
IloczynKartezjanski
dodaj dwa prywatne pola:
•
zbiory
, które będzie przechowywać tablicę ze zbiorami (typ
array
),
•
wynik
, które będzie przechowywać wynik obliczeń (typ
array
).
2. Dodaj publiczne metody
get
i
set
dla pól.
3. Dodaj publiczną bezparametrową metodę
oblicz
. Uzupełnij kod zgodnie ze
wskazówkami z punktu 4.
Uzupełnij pola klasy
IloczynKartezjanski
o informacje o ich typie. Uzupełnij komentarze przed
metodami o informację o typach parametrów i wartości zwracanej przez metody.
3.5. Główny program
Algorytm obliczania iloczynu kartezjańskiego (do metody
main
klasy
ProgramJAO
) jest
następujący:
1. Utwórz nowy obiekt
odczytDanych
klasy
OdczytDanych
.
2. W obiekcie
odczytDanych
ustaw metodą
setNazwaPliku
plik, z którego będą odczytane
zbiory.
3. Używając metody
odczytaj
odczytaj dane z pliku.
4. Pobierz listę zbiorów z obiektu
odczytDanych
metodą
getZbiory
.
5. Utwórz nowy obiekt
iloczynKartezjański
klasy
IloczynKartezjański
.
6. Ustaw listę zbiorów, z których obliczymy iloczyn kartezjański.
7. Wykonaj obliczenia, wywołując metodę
oblicz
obiektu
iloczynKartezjański
.
8. Pobierz wynik z obiektu
iloczynKartezjański
i zapisz go w polu
wynik
.
Zaimportuj pliki z deklaracjami klas
IloczynKartezjański
i
OdczytDanych
.
Pisząc kod, wstawiaj w komentarzach odwołania do punktów algorytmu, np.:
$odczyDanych = new OdczytDanych(); //punkt 1
© G. Dec, 2010
5
3.6. Koniec ćwiczenia
Sprawdź, czy:
1. Program napisany przez ciebie wykonuje się bez błędów i realizuje cel ćwiczenia.
2. Program składa się z pięciu plików:
dane.txt
,
index.php
,
ProgramJAO.php
,
IloczynKartezjański.php
i
OdczytDanych.php
.
3. Plik
index.php
zawiera instrukcję dołączenia pliku
ProgramJAO.php
i 3 linijki kodu.
4. W pliku
ProgramJAO.php
znajduje się wyłącznie klasa
ProgramJAO
.
5. W pliku
IloczynKartezjański.php
znajduje się wyłącznie klasa
IloczynKartezjański
.
6. W pliku
OdczytDanych.php
znajduje się wyłącznie klasa
OdczytDanych
.
7. Klasa
ProgramJAO
zawiera jedno publiczne pole o nazwie
wynik
i jedną publiczną
bezparametrową metodę o nazwie
main
.
8. Kod wpisany do metody
main
klasy
ProgramJAO
jest zgodny z algorytmem z punktu 3.5.
9. Linie kodu z metody
main
klasy
ProgramJAO
zawierają w komentarzach odnośniki
do punktów algorytmu.
Zamknij projekt w środowisku Netbeans. Zarchiwizuj katalog z projektem i prześlij go na adres
e-mail podany przez osobę prowadzącą zajęcia.
4. Wskazówki do wykonania ćwiczenia
Obliczanie iloczynu kartezjańskiego N zbiorów można wykonać wykorzystując właściwość rozdziel-
ności tej operacji. Chcąc obliczyć
IK = A
1
×A
2
×A
3
×A
4
możemy zastosować podejście iteracyjne:
IK
1
= A
1
×A
2
IK
2
= IK
1
×A
3
IK = IK
2
×A
4
Widać wyraźnie, że do obliczenia iloczynu kartezjańskiego N zbiorów należy użyć N-1 razy funkcji
obliczającej iloczyn kartezjański dwóch zbiorów.
W klasie
IloczynKartezjanski
utwórzmy metodę obliczającą iloczyn kartezjański dwóch zbio-
rów:
© G. Dec, 2010
6
Teraz utworzymy właściwą metodę obliczającą iloczyn kartezjański, która używa metody
oblicz2zb
:
public void oblicz() {
//jeżeli pole zbiory ma mniej niż 2 elementy, zakończ funkcję
//do pola wynik przypisz element 0 pola zbiory
//dla każdego elementu e z pola zbiory, zaczynając od 1:
//oblicz IK zbioru z pola wynik i elementu e używając oblicz2zb
//i zapamiętaj wynik obliczeń w polu wynik
}
Ilość elementów tablicy zwróci funkcja
count
:
$ilosc = count($tablica);
Iteracje po tablicach możemy wykonać przy pomocy instrukcji:
for($i=1; $i<$ilosc; $i++) { $element = $tablica[$i]; .... }
Innym sposobem na iteracje po wszystkich elementach tablicy jest instrukcja:
foreach($tablica as $element) { print_r($element);}
5. Sprawozdanie
Na stronie internetowej z materiałami dydaktycznymi znajduje się szablon sprawozdania
z ćwiczenia 2. Należy go zastosować do wykonania sprawozdania.
6. Pytania na wejściówkę
1. Czy do wykonania tego ćwiczenia potrzebny jest projekt Netbeans z poprzednich zajęć?
2. W języku C, zadeklaruj strukturę o nazwie PUNKT. Dodaj do struktury dwa pola typu
całkowitego o nazwach
x
i
y
. Zadeklaruj typ strukturalny o nazwie Punkt oparty o strukturę
PUNKT.
3. W języku C, utwórz zmienną o nazwie punkt typu Punkt zdefiniowany w zadaniu 1. Przypisz
wartości 1, 2 odpowiednio do pól
x
i
y
zmiennej punkt.
4. W języku C, utwórz zmienną typu wskaźnikowego na typ Punkt zdefiniowany w zadaniu 2.
Używając dynamicznej alokacji pamięci, zarezerwuj obszar pamięci o rozmiarze typu Punkt
i przypisz wskaźnik do tej pamięci do zadeklarowanej zmiennej.
5. W jaki sposób w języku PHP wykonać iterację po wszystkich elementach tablicy?
(Odpowiedź jest w punkcie 4.)
6. W jaki sposób w języku PHP wykonać iterację po wszystkich elementach tablicy, zaczynając
od elementu o indeksie 2? Zakładamy, że w tablicy jest przynajmniej 3 elementy. (Odpowiedź
jest w punkcie 4.)
© G. Dec, 2010
7