Inżynieria oprogramowania
Wykład III. HELLO WORLD!
Politechnika Radomska
O czym będzie ?
Klasy i komponenty
Modele statyczne i dynamiczne
Związki między modelami
Rozszerzanie UML
Dlaczego „HELLO
WORLD!”
Autorzy języka C, Brian Kernighan i Dennis Ritchie,
zauważyli, że jedyną metodą nauczenia się języka
programowania jest pisanie w nim programów. Tak
samo jest z UML. Jedyną drogą do opanowania tego
języka jest opracowywanie w nim modeli.
Wielu programistów rozpoczyna naukę nowego języka
od napisania w nim prostego programu, który wyświetla
na ekranie napis „Hello, World!". Stanowi to dobry
punkt wyjścia, ponieważ natychmiastowe ukończenie
banalnego programu przynosi wiele satysfakcji, a poza
tym umożliwia także zapoznanie się z warunkami, w
jakich wytwarza się i uruchamia oprogramowanie.
My zrobimy tak samo
Tak samo rozpoczniemy naukę języka UML.
Modelowanie „Hello, World!" to prawdopodobnie
najprostszy przykład zastosowania UML, z jakim
się kiedykolwiek zetkniesz.
Prostota tego programu jest jednak zwodnicza;
kryje on bowiem w sobie kilka ciekawych
mechanizmów sprawiających, że to wszystko
działa.
Można
łatwo
utworzyć
modele
tych
mechanizmów i uzyskać pełniejszy obraz
konstrukcji tego prostego programu.
Tekst modelowanego
programu (Java)
Aplet do wyświetlania w przeglądarce WWW napisu
„Hello, World!” można w Javie zaprogramować
bardzo prosto:
import java.awt.Graphics;
class HelloWorld extends java.applet.Applet {
public void paint (Graphics g) {
g.drawString ("Hello, World!",
10,
10);
}
}
Analiza działania
programu
Pisząc w pierwszym wierszu
import java.awt.Graphics;
sprawiamy, że w dalszej części
programu można bezpośrednio
używać klasy Graphics.
Przedrostek java.awt określa pakiet
Javy, w którym tę klasę zdefiniowano.
Analiza działania
programu
W drugim (i trzecim) wierszu:
class HelloWorld extends
java.applet.Applet {
wprowadzamy nową klasę o nazwie
HelloWorld i określamy, że jest to
potomek klasy Applet zdefiniowanej
w pakiecie java.applet.
Analiza działania
programu
W następnych wierszach:
public void paint (Graphics g) {
g.drawString ("Hello, World!",
10, 10);
}
deklarujemy operację paint.
W wyniku jej implementacji zostaje wywołana inna
operacja (drawString) odpowiedzialna za wyświetlenie
„Hello, World!” w miejscu o podanych współrzędnych.
Tak jak zwykle w programach obiektowych, drawString
jest operacją na argumencie g, którego typem jest klasa
Graphics.
Podstawowe abstrakcje
dla HelloWorld
Opracowanie modelu tego programu w UML jest
bardzo łatwe. Jak widać na rysunku, klasę
HelloWorld można przedstawić jako prostokąt.
Uwzględniliśmy także przypisaną jej operację paint.
ale bez parametrów formalnych.
Implementację paint zobrazowaliśmy w postaci
dołączonej notatki.
Uwaga !
UML nie jest językiem programowania graficznego,
choć, jak widać na poprzednim rysunku, umożliwia
ścisłe powiązanie z pewnymi językami (np. z Javą).
UML zaprojektowano tak, aby było możliwe
przekształcenie modeli w kod, a także odtwarzanie
modeli z programów (z wykorzystaniem inżynierii
wstecz).
Pewne fakty łatwiej zapisać z użyciem składni
tekstowego języka programowania (np. wyrażenia
matematyczne), a inne łatwiej wyrazić graficznie w
UML (np. hierarchię klas).
Bezpośredni sąsiedzi
HelloWorld
Na tym diagramie klas są przedstawione podstawowe
elementy programu „Hello, World!”, ale brakuje innych -
niemniej ważnych.
W programie są używane jeszcze dwie klasy: Applet i
Graphics, a co więcej, każda inaczej.
Applet jest przodkiem klasy HelloWorld, a Graphics
występuje w sygnaturze oraz implementacji operacji
paint. Te dwie dodatkowe klasy i ich związki z HelloWorld
można przedstawić tak jak pokazano na rysunku.
Analiza diagramu
Klasy Applet i Graphics są przedstawione jako
prostokąty.
Ich operacje nie zostały uwzględnione, a zatem
nie ma na rysunku obrazujących ich symboli.
Strzałka
z
niewypełnionym
grotem,
od
HelloWorld do Applet, przedstawia uogólnienie,
które w tym wypadku oznacza, że HelloWorld
jest potomkiem klasy Applet.
Przerywana strzałka od HelloWorld do Graphics
obrazuje zależność, która polega na tym, że
HelloWorld korzysta z klasy Graphics.
Diagram klas
To jeszcze nie koniec szkieletu, na którym zbudowano
HelloWorld.
Po przejrzeniu bibliotek definiujących w Javie klasy Applet
i Graphics stwierdzisz, że obie są częścią bardziej
złożonej hierarchii. Prześledziwszy wszystkie klasy
rozszerzane i implementowane przez Applet, możesz
opracować diagram klas przedstawiony na rysunku.
Co wynika z diagramu
klas ?
Uwaga: Diagram na poprzednim rysunku to wynik
zastosowania inżynierii wstecz, która polega na
odtworzeniu modelu z kodu programu.
Z rysunku wynika, że HelloWorld jest liściem w większej
hierarchii klas. Klasa HelloWorld jest potomkiem klasy
Applet, Applet potomkiem klasy Panel, Panel
potomkiem klasy Container, Container potomkiem
klasy Component, a Component potomkiem klasy Object,
która jest klasą macierzystą (przodkiem) dla wszystkich
klas zdefiniowanych w Javie.
Przedstawiony model dokładnie oddaje zawartość
biblioteki Javy - każdy potomek stanowi rozszerzenie
pewnej klasy macierzystej.
Co wynika z diagramu
klas ?
Związek między ImageObserver a Component jest
innej natury. Diagram klas odzwierciedla tę różnicę.
ImageObserver jest w bibliotece Javy interfejsem,
co oznacza, że nie obejmuje implementacji. Musi
być ona zapewniona przez klasy.
Jak widać na rysunku, interfejs jest w UML
obrazowany jako okrąg. Fakt implementacji przez
Component
interfejsu
ImageObserver
jest
przedstawiony w postaci linii ciągłej, łączącej
Component z ImageObserver.
Pakiety
Jak wynika z przedstawionych tu rysunków, HelloWorld bezpośrednio
współpracuje jedynie z dwiema klasami (Applet i Graphics), które
stanowią tylko niewielką część biblioteki klas predefiniowanych w
Javie.
Opanowanie tej ogromnej liczby klas jest możliwe dzięki podzieleniu
ich na pakiety. Główny pakiet w środowisku Javy ma oczywiście
nazwę java. Zawiera inne pakiety, które z kolei składają się z
pakietów, klas i interfejsów.
Object to element pakietu lang, a zatem pełna nazwa ścieżki
dostępu do niego to java.lang.Object. Podobnie Panel, Container
i Component są składowymi awt, a Applet pakietu applet.
Interfejs ImageObserver jest zdefiniowany w pakiecie image, który z
kolei jest elementem pakietu awt, a zatem pełna nazwa ścieżki
dostępu
do
niego
jest
dość
długa:
java.awt.image.ImageObserver.
Struktura pakietów
HelloWorld
Omówioną tu strukturę pakietów można
zobrazować za pomocą diagramu klas
Zależności pomiędzy
pakietami
W UML pakiety przedstawia się za
pomocą prostokątów z bolcami.
Pakiety mogą być zagnieżdżone;
zależności między nimi obrazuje się
linią przerywaną zakończoną grotem.
Klasa HelloWorld zależy na przykład
od pakietu java.applet, a ten od
java.awt.
Współpraca elementów w
bibliotekach
Najtrudniejsze w opracowywaniu tak złożonych
bibliotek jak te występujące w Javie jest
zrozumienie, jak ich elementy współpracują.
W jaki sposób jest wywoływana operacja paint
klasy HelloWorld? Jakich operacji należy użyć,
aby zmienić zachowanie tego apletu (np.
wyświetlić napis w innym kolorze)?
Znalezienie odpowiedzi na te pytania musi być
poprzedzone
opracowaniem
modelu
pojęciowego
przedstawiającego
sposób
współpracy tych klas.
Mechanizm wyświetlania
Po przebadaniu
biblioteki
Javy
dochodzi się do
wniosku,
że
operacja paint
klasy
HelloWorld jest
dziedziczona po
klasie
Component. Nie
wyjaśnia
to
jednak
wcale,
jak
jest
ona
wywoływana.
Odpowiedź znajdziesz na rysunku.
Operacja paint jest wywoływana
przez wątek, w skład którego
wchodzi nasz aplet.
Kooperacja obiektów dla
wywołania metody paint
Na rysunku widać kooperację kilku obiektów, wśród
których jest także egzemplarz klasy HelloWorld.
Pozostałe obiekty są składowymi środowiska Javy i
występują w tle wszystkich tworzonych apletów.
W UML egzemplarze są przedstawiane tak samo
jak klasy, z tą tylko różnicą, że ich nazwy są
podkreślone.
Pierwsze trzy obiekty na tym diagramie są
anonimowe - nie mają unikatowej nazwy.
Obiekt klasy HelloWorld ma nazwę target,
rozpoznawaną przez obiekt klasy ComponentPeer.
Kooperacja obiektów dla
wywołania metody paint
Do modelowania kolejności zdarzeń służy diagram
przebiegu.
Wszystko zaczyna się od uruchomienia (run) obiektu
klasy Thread, który z kolei wywołuje operację run
obiektu klasy Toolkit. Obiekt ten uruchamia jedną ze
swoich operacji (callbackLoop), która z kolei powoduje
wywołanie handleExpose obiektu ComponentPeer. Ten
obiekt wywołuje operację paint swego odbiorcy.
Przyjmuje, że tym odbiorcą jest egzemplarz klasy
Component, ale w tym wypadku jest to potomek tej klasy
HelloWorld, a zatem wywołanie operacji paint jest tu
polimorficzne.
Komponenty
Program „HelloWorld!” jest apletem, a zatem nie działa
samodzielnie, lecz jest częścią jakiejś witryny internetowej.
Aplet jest uruchamiany z chwilą otwarcia tej witryny, a jego
działanie jest inicjowane przez przypisany mu obiekt klasy
Thread.
Klasa HelloWorld nie jest jednak bezpośrednio składową
witryny. Występuje tam w postaci binarnej, wygenerowanej
przez kompilator Javy, który przekształca kod źródłowy w
komponent wykonywalny.
Te rozważania prowadzą do zupełnie innego spojrzenia na
system.
Na
wszystkich
przedstawionych
dotychczas
diagramach braliśmy pod uwagę logiczne właściwości apletu,
a teraz mamy do czynienia z jego fizycznymi komponentami.
Diagram komponentów
Do modelowania struktury komponentów
służy diagram komponentów.
Perspektywa
implementacyjna
Wszystkie
symbole na rysunku obrazują
elementy UML z perspektywy implementacyjnej.
Komponent o nazwie hello.java reprezentuje
kod źródłowy klasy logicznej HelloWorld. Jest on
zatem plikiem, który może być przetwarzany
przez zintegrowane środowisko programistyczne,
a także narzędzia wspomagające zarządzenie
konfiguracjami. Z tego kodu źródłowego można
za pomocą kompilatora Javy otrzymać aplet w
postaci binarnej HelloWorld.class, nadający
się do realizacji przez maszynę wirtualną Javy.
Składowe komponentu
Komponent jest wyrażany na diagramie jako
prostokąt z dwoma bolcami.
Symbol
przedstawiający
aplet
binarny
HelloWorld.class jest wariantem symbolu
komponentu. Brzegi prostokąta są pogrubione,
co
oznacza,
że
chodzi
o
komponent
wykonywalny (podobnie jak klasa aktywna).
Symbol
komponentu
hello.java
jest
niestandardowy; zastąpiliśmy go ikoną, która
reprezentuje plik tekstowy.
Składowe komponentu
Dopasowaliśmy też symbol witryny hello.html
do naszych potrzeb. Było to możliwe dzięki
rozszerzeniu notacji UML.
Jak było widać na rysunku, witryna zawiera
jeszcze jeden komponent o nazwie hello.jpg,
zobrazowany także za pomocą symbolu spoza
UML, a mianowicie miniatury grafiki witryny.
Ponieważ
jednak
ostatnie
komponenty
przedstawiliśmy na diagramie za pomocą
nietypowych symboli, ich nazwy zostały
umieszczone obok symboli.
Uwaga !
Nie modeluje się na ogół związków między klasą
(HelloWorld), jej kodem źródłowym (hello.java) i
jej kodem binarnym (HelloWorld.class), choć
niekiedy zobrazowanie ich mogłoby ułatwić
zrozumienie fizycznej konfiguracji systemu.
Znacznie częściej przedstawia się graficznie
organizację
oprogramowania
WWW.
Do
modelowania jego witryn i innych komponentów
wykonywalnych
używa
się
diagramów
komponentów.