Cel i zakres trzeciego wykładu

Transkrypt

Cel i zakres trzeciego wykładu
Cel i zakres trzeciego wykładu
Tytuł: Diagramy sekwencji, pakietów, stanu i wdrożenia w perspektywie
implementacyjnej
Cel wykładu:
Zaprezentować sposób przygotowania wyżej wymienionych diagramów w
perspektywie implementacyjnej.
Zakres wykładu
1) Zasady tworzenia diagramów sekwencji
2) Zasady tworzenia diagramów pakietów
3) Sposoby implementacji diagramów stanów
4) Zasady tworzenia diagramów wdrożeń
Projektowanie systemów informatycznych, wykład 3
1
1
Diagramy sekwencji
Diagram
sekwencji
przedstawia sposób wymiany
komunikatów
pomiędzy
obiektami z zachowaniem ich
kolejności. Pomijają natomiast
całkowicie aspekt dostępu i
operacji na danych, związany z
komunikacją.
Uczestnikami
diagramów
sekwencji są obiekty, opisane
nazwą obiektu i jego klasą,
które wymieniają między sobą
komunikaty.
Projektowanie systemów informatycznych, wykład 3
2
Diagramy interakcji to modele opisujące, jak współpracują ze sobą grupy obiektów. UML definiuje kilka rodzajów
diagramów interakcji, z których najczęściej używanym jest diagram sekwencji.
Zwykle diagram sekwencji przedstawia zachowanie się systemu dotyczące jednego przypadku użycia. Diagram
pokazuje kilka przykładowych obiektów i komunikaty przez nie wymieniane w ramach przypadku użycia.
Pierwszy przykładowy diagram sekwencji będzie dotyczył następującego prostego scenariusza: załóżmy że mamy
zamówienie i zamierzamy wywołać na nim polecenie obliczające wartość tego zamówienia. W tym celu najpierw
należy wybrać wszystkie pozycje zamówienia i określić ich ceny na podstawie reguł cenowych ustalonych dla
zamawianych produktów. Następnie zamówienie musi obliczyć ogólną zniżkę, obliczaną na podstawie reguł
ustalonych dla danego klienta.
Na rysunku został przedstawiony diagram sekwencji ukazujący jedną z możliwych implementacji tego scenariusza.
Diagramy sekwencji ilustrują interakcje wymieniając każdego jej uczestnika razem z pionową linią oznaczającą
czas, w którym ten uczestnik bierze udział w interakcji. Kolejno pojawiające się komunikaty są uporządkowane od
góry do dołu. Widać wyraźnie, że instancja klasy Zamówienie wysyła komunikaty pobierzllość i pobierzProdukt
do klasy Pozycje Zamówienia. Można też dostrzec, jak jest zapisywana metoda wywoływana przez klasę
Zamówienie na sobie samej, oraz to, że inna wywoływana w ten sposób metoda wysyła komunikat
pobierzInformacjeOZniżkach do instancji klasy Klient.
Diagram jednak nie przedstawia wszystkiego bardzo dobrze. Sekwencja komunikatów pobierzllość,
pobierzProdukt, pobierzCennik oraz obliczCenę jest wysyłana dla każdej pozycji zamówienia, natomiast
obliczZniżkę jest wywoływana tylko raz. Nie można na podstawie tego diagramu stwierdzić, że tak jest, chociaż
można wprowadzić dodatkową notację, która to umożliwi.
Na przedstawionych diagramach nadano uczestnikom nazwy składające się tylko z nazwy obiektu. Pełniejsza
składnia ma postać nazwaObiektu : nazwaKIasy, gdzie zarówno nazwa obiektu, jak i nazwa klasy może być
pominięta. Jeśli opuści się nazwę obiektu, to trzeba pozostawić dwukropek. Na każdej linii czasu są umieszczane
słupki aktywności reprezentujące chwile, w których uczestnik bierze udział w interakcji. Oznaczają one obecność
jednej z metod uczestnika na stosie wywołań. Słupki aktywności są w UML-u opcjonalne.
Odpowiednie nazewnictwo często pomaga w powiązaniu uczestników na diagramie. Wywołanie komunikatu
pobierzProdukt zwraca Produkt mający tę samą nazwę, a więc będący tym samym uczestnikiem, co Produkt, do
którego jest wysyłany komunikat pobierzCennik. Proszę zwrócić uwagę na to, że użyto strzałki zwrotnej tylko w
tym wywołaniu tak aby podkreślić istnienie odpowiedniości. Można używać strzałek zwrotnych we wszystkich
wywołaniach, ale lepiej stosować je tylko tam, gdzie niosą one dodatkową informację. Pierwszy komunikat nie ma
wysyłającego go uczestnika i nadchodzi z nieokreślonego źródła. Jest nazywany komunikatem wykrytym.
2
Inna wersja diagramu sekwencji z pop. slajdu
Projektowanie systemów informatycznych, wykład 3
3
Inne podejście do tego samego scenariusza zostało pokazane na aktualnym slajdzie. Podstawowy problem
pozostaje ten sam, ale sposób, w który uczestnicy współpracują ze sobą w celu jego rozwiązania, jest zupełnie
inny. Zamówienie prosi każdą PozycjęZamówienia, aby obliczyła swoją własną Cenę. PozycjaZamówienia
następnie zleca wykonanie obliczenia ceny wszystkim instancjom klasy produkt, które znajdują się na liście
zamówienia. Tu warto zwrócić uwagę na to, jak jest przedstawione przekazywanie parametru. Podobnie, aby
obliczyć wysokość zniżki, Zamówienie wywołuje metodę na Kliencie. Klient do wykonania swojego zadania
potrzebuje dodatkowej informacji z Zamówienia, więc wywołuje na Zamówieniu metodę
pobierzCenęPodstawową w celu pobrania danych.
Pierwsze, co można powiedzieć na temat tych dwóch ostatnich diagramów, jest to, że diagram sekwencji
bardzo jasno przedstawia różnice we wzajemnej komunikacji uczestników. To jest ogromna zaleta diagramów
interakcji. Nie nadają się one dobrze do przedstawiania szczegółów algorytmów, takich jak pętle lub
zachowania warunkowe, ale wywołania między uczestnikami ukazują wyjątkowo przejrzyście i dają naprawdę
dobry obraz działań wykonywanych przez poszczególnych uczestników.
Drugą sprawą jest oczywista różnica w stylach między dwiema zaprezentowanymi interakcjami. Na
poprzednim slajdzie przedstawiono sterowanie scentralizowane, w którym jeden z uczestników wykonuje
zdecydowaną większość zadań, a inni uczestnicy dostarczają tylko dane. Na aktualnym slajdzie pokazano
sterowanie rozproszone, w którym przetwarzanie jest rozdzielone między wielu uczestników i każdy z nich
wykonuje mały fragment algorytmu. Oba style mają swoje wady i zalety. Wiele osób, zwłaszcza tych, które
mają małe doświadczenie w technikach obiektowych, jest bardziej przyzwyczajonych do sterowania
scentralizowanego. Z wielu względów jest ono mniej skomplikowane, ponieważ całe przetwarzanie dokonuje
się w jednym miejscu. Przy sterowaniu rozproszonym można odnieść wrażenie, że ciągle skacze się po
różnych obiektach, a sam program jakoś trudno uchwycić.
Pomimo to, w projektowaniu obiektowym preferuje się sterowanie rozproszone. Jednym z zadań dobrego
projektu jest zlokalizowanie efektów zachodzących zmian. Dane i metody, które uzyskują dostęp do tych
danych, często zmieniają się równocześnie. A więc umieszczenie danych i metod ich używających razem w
jednym miejscu, jest najważniejszą zasadą projektowania obiektowego. Ponadto, sterowanie rozproszone daje
więcej okazji do użycia polimorfizmu zamiast logiki warunkowej. Jeśli algorytmy ustalania cen produktów są
różne dla różnych typów produktów, to mechanizm sterowania rozproszonego pozwala na użycie klas
pochodnych klasy Produkt w celu poprawnego uwzględnienia tych różnic.
Ogólnie styl obiektowy daje możliwość użycia wielu małych obiektów z wieloma małymi metodami, dających
mnóstwo okazji do zastosowania przeciążania funkcji i różnych ich wariacji. Jest to coś, czego bardzo trudno
nauczyć. Wydaje się, że jedynym sposobem na zrozumienie tego podejścia jest popracowanie w środowisku
obiektowym o silnie rozproszonym sterowaniu.
3
Tworzenie i usuwanie obiektów
Projektowanie systemów informatycznych, wykład 3
4
Na diagramach sekwencji można stosować pewną dodatkową notację oznaczającą
tworzenie i usuwanie uczestników. Aby utworzyć uczestnika, należy narysować strzałkę
komunikatu łączącą się bezpośrednio z prostokątem uczestnika. Nazwa komunikatu jest
w tym wypadku opcjonalna. Można tę nazwę opisać typem konstruktora, którego
wywołuje się do tworzenia obiektu. Nazwa „nowy” jest uniwersalna i nie pokazuje,
którego konstruktora użyto. Jeśli uczestnik zaraz po pojawieniu się wykonuje jakąś
czynność, na przykład wywołuje komunikat kwerendy, to słupek aktywacji jest
umieszczany bezpośrednio pod prostokątem uczestnika.
Usunięcie uczestnika jest oznaczane dużym krzyżykiem w kształcie litery X.
Strzałka komunikatu skierowana w stronę tego krzyżyka oznacza, że jeden uczestnik
jawnie usuwa innego uczestnika. Krzyżyk umieszczony na końcu linii czasu oznacza, że
uczestnik usuwa się sam.
W środowisku, w którym zwalnianie pamięci przebiega automatycznie (Java, .NET) nie
usuwa się obiektów bezpośrednio, ale nadal warto używać krzyżyków w celu wskazania,
kiedy obiekt już przestaje być potrzebny i jest gotowy do usunięcia. Jest
to również wskazane dla operacji zamykania, w celu zaznaczenia, że obiekt nie będzie
już używany.
4
Rodzaje komunikatów
Projektowanie systemów informatycznych, wykład 3
5
W nowej wersji języka UML strzałka z wypełnionym grotem oznacza komunikat
synchroniczny, a strzałka z grotem otwartym należy do komunikatu asynchronicznego.
Jeśli obiekt wysyła komunikat synchroniczny, to musi zaczekać na jego zrealizowanie,
na przykład na wykonanie podprocedury. Jeśli natomiast obiekt wysyła komunikat
asynchroniczny, to może kontynuować przetwarzanie, nie czekając na odpowiedź.
Komunikaty asynchroniczne występują w aplikacjach wielowątkowych i w
oprogramowaniu pośredniczącym opartym na komunikatach. Asynchroniczność
umożliwia szybsze reagowanie i redukuje występowanie sprzężeń czasowych, ale
utrudnia wykrywanie błędów w kodzie programu.
5
Pętle i instrukcje warunkowe
procedure wysłanie
foreach (pozycjazamówienia)
if (produktwartość > 10000 zł)
ostrożny.wysłanie
else
zwykły.wysłanie
end if
end for
if (wymaganePotwierdzenie)
komunikator.potwierdzenie
end procedurę
Projektowanie systemów informatycznych, wykład 3
6
Częstym problemem towarzyszącym diagramom sekwencji jest to, jak pokazać pętle i zachowania
warunkowe. Przede wszystkim warto od razu zaznaczyć, że nie jest to coś, przy czym diagramy
sekwencji dobrze się spisują. Aby pokazać tego typu struktury sterujące, znacznie lepiej użyć
diagramu czynności lub nawet samego kodu programu. Diagramy sekwencji należy traktować jako
sposób wizualnego przedstawienia, w jakie interakcje wchodzą ze sobą obiekty, a nie jako sposób
modelowania logiki sterującej systemem.
Jeśli chodzi o samą notację, to zarówno pętle, jak i instrukcje warunkowe korzystają z ramek
interakcji, które służą do wyróżnienia fragmentu diagramu sekwencji. Na slajdzie zilustrowano
nieskomplikowany algorytm oparty na pseudokodzie zaprezentowanym na lewo od diagramu.
Ogólnie, ramki składają się z pewnego obszaru diagramu sekwencji, który może być dodatkowo
podzielony na kilka fragmentów. Każda ramka ma operator a każdemu wydzielonemu fragmentowi
ramki może towarzyszyć warunek. Aby przedstawić pętlę, używa się operatora loop i jednego
fragmentu ramki, a podstawę iteracji umieszcza się w warunku. Dla instrukcji warunkowej można
użyć operatora alt, a w każdym fragmencie ramki umieścić warunek. Zostaje wykonany tylko ten
fragment, którego warunek jest prawdziwy. Jeśli istnieje tylko jeden obszar, to rządzi nim operator
opt.
Ramki interakcji są nowością w UML-u 2.0. Na diagramach przygotowanych przed pojawieniem się
UML-a 2.0 stosowano inne podejścia.
6
Operatory ramek interakcji
alt (od alternative) – określający warunek wykonania bloku operacji, odpowiadający
instrukcji if-else; warunek umieszcza się wówczas wewnątrz bloku w nawiasach
kwadratowych
opt (od optional) – reprezentujący instrukcję if (bez else). Fragment zostaje wykonany
tylko wówczas, gdy zawarty w nim warunek jest prawdziwy. Jest to odpowiednik
operatora alt z jednym wyjściem.
par (od parallel) – nakazujący wykonać operacje równolegle
Loop - definiujący pętlę typu for (o określonej z góry liczbie iteracji) lub while
(wykonywanej dopóki pewien warunek jest prawdziwy)
critical – oznaczający obszar krytyczny. Fragment może mieć tylko jeden wątek
uruchomiony w danej chwili.
neg – (od negation)Negacja. Fragment przedstawia niepoprawną interakcję. W ten
sposób opisujemy niepożądane interakcje w systemie.
ref – (od reference) Referencja. Odwołuje się do interakcji zdefiniowanej na innym
diagramie. Ramka jest rysowana tak, aby przykrywać linie czasu biorące udział w
interakcji. Można zdefiniować parametry i wartość zwrotną.
sd – (od sequence diagram) Diagram sekwencji. Używany do otoczenia ramką całego
diagramu sekwencji, w miarę potrzeby.
Projektowanie systemów informatycznych, wykład 3
7
7
Kiedy używać diagramów sekwencji
Należy stosować diagramy sekwencji, aby spojrzeć na zachowanie się kilku
obiektów w ramach jednego przypadku użycia systemu. Diagramy sekwencji są
użyteczne do przedstawiania współpracy obiektów — nie są jednak najlepsze do
podawania ścisłej definicji zachowań.
Do obserwowania zachowania się jednego obiektu w ramach kilku przypadków
użycia należy zastosować diagram stanów. Do badania zachowania w wielu
przypadkach użycia lub wielu wątkach należy rozważyć zastosowanie diagramów
czynności.
Projektowanie systemów informatycznych, wykład 3
8
8
Diagramy pakietów (1)
Pakiet jest elementem grupującym pozwalającym na pogrupowanie dowolnych
bytów UML-a w jednostki wyższego poziomu. Najczęstszym sposobem
użycia pakietów jest grupowanie klas. Właśnie to użycie zostanie
zaprezentowane w tym fragmencie wykładu.
W modelu UML:
•
Każda klasa jest składnikiem jednego pakietu
•
Pakiety mogą być składnikami innych pakietów. Umożliwia to utworzenie
hierarchicznej struktury, w której pakiety najwyższego poziomu są
podzielone na mniejsze pakiety mające swoje własne podpakiety itd., aż
hierarchia osiągnie najniższy poziom w postaci klas.
•
Pakiet może zawierać zarówno pakiety podrzędne, jak i klasy.
•
W językach programowania pakiety odpowiadają takim elementom, jak
pakiety w Javie i przestrzenie nazw w językach C++ i .NET.
Projektowanie systemów informatycznych, wykład 3
9
Klasy są podstawowym składnikiem struktury systemu obiektowego. Są bardzo przydatne, jednak do
tworzenia struktury ogromnych systemów, mających po kilkaset klas, potrzeba czegoś więcej. UML
umożliwia grupowanie klas w pakiety. Diagramy pakietów służą do bardzo ogólnej prezentacji
systemu. Pakiety są wykonywane w perspektywie projektowej lub implementacyjnej stąd na
wykładzie z modelowania systemów informatycznych tego typu diagramy nie były prezentowane.
Każdy pakiet reprezentuje przestrzeń nazw, co oznacza, że każda klasa musi mieć jednoznaczną
nazwę wewnątrz zawierającego ją pakietu. Jeśli chcemy utworzyć klasę o nazwie Data i klasa Data
już istnieje w pakiecie System, to nadal możemy mieć klasę Data, jeśli umieścimy ją w odrębnym
pakiecie. Aby rozpoznać, która jest która, można użyć w pełni kwalifikowanej nazwy, tzn. nazwy
uwzględniającej również zawierający klasę pakiet. Do określania nazw pakietów w UML-u używa się
podwójnych dwukropków, więc na przykład klasy Data mogłyby mieć nazwy System::Data oraz
MartinFowler::Użytkil::Data.
9
Diagramy pakietów (2)
Projektowanie systemów informatycznych, wykład 3
10
Na diagramach pakiety są oznaczane za pomocą folderów z zakładkami. Na rysunku pokazano przykład
takiego diagramu. Można uwidocznić tylko nazwę pakietu lub też jego zawartość. Wszędzie można
używać zamiennie w pełni kwalifikowanych nazw lub zwykłych nazw prostych. Zawartość pakietu można
przedstawić za pomocą ikon klas i uwzględnić wszystkie szczegóły klasy, nawet do poziomu diagramu
klasy. Wypisanie samych nazw klas ma sens wtedy, gdy chcemy jedynie wskazać, jakie klasy znajdują się
w poszczególnych pakietach.
Znacznie częściej spotyka się krótkie nazwy klas, takie jak Datę (z pakietu java.util), niż nazwy w pełni
kwalifikowane.
W UML-u klasy w pakietach mogą być publiczne lub prywatne. Klasa publiczna jest częścią interfejsu
pakietu i może być używana przez inne pakiety. Klasa prywatna jest ukryta. W różnych środowiskach
programistycznych stosuje się różne reguły dotyczące zakresów widoczności występujących między
poszczególnymi elementami pakietów. Należy przestrzegać konwencji środowiska programistycznego,
nawet jeśli wymaga to nagięcia zasad UML-a.
Dobrą praktyką jest ograniczenie interfejsu pakietu do niewielkiego podzbioru operacji klas publicznych.
Można to osiągnąć, nadając wszystkim klasom prywatny zasięg widoczności, tak aby były one widziane
tylko przez inne klasy tego pakietu, i dorzucając do pakietu dodatkowe klasy publiczne dla definicji
zachowania publicznego. Te dodatkowe klasy, zwane fasadami, zlecają wykonanie operacji publicznych
ich prywatnym partnerom w ramach pakietu.
W jaki sposób zdecydować, które klasy umieścić w poszczególnych pakietach? Jest to dość trudne pytanie
i aby umieć na nie odpowiadać, trzeba posiąść duże umiejętności w dziedzinie projektowania.
Pakiety powinny być tworzone tak aby były jak najbardziej spójne wewnętrznie i aby było jak najmniej
zależności między pakietami. Każdy nowy element wstawiany do pakietu powinien stanowić pełną całość
wraz z pozostałymi elementami w pakiecie (powinien być z nimi w pewien sposób powiązany). Dobrym
testem na sprawdzenie czy pakiet jest spójny może być próba nadania krótkiej nazwy pakietowi. Jeżeli
istnieją problemy z nadaniem takiej nazwy to prawdopodobnie można dodać do pakietu niepowiązane
elementy.
10
Zależności między pakietami
Diagram pakietów przedstawia pakiety i zależności między nimi. Pojęcie zależności
wprowadziłem na poprzednim wykładzie slajd 20. Jeżeli w pakiecie A istnieje
przynajmniej jedna klasa, która jest zależna od przynajmniej jednej klasy pakietu B to
mówimy, że pakiet A jest zależny od pakietu B. W ten sposób zależności między
pakietami podsumowują zależności między zawartościami tych pakietów.
Projektowanie systemów informatycznych, wykład 3
11
UML wymienia wiele różnych zależności, z których każda ma własną semantykę i słowo
kluczowe. Zwykle jednak łatwiej jest zaczynać od ogólnych zależności bez słów kluczowych, a
dopiero później, w miarę potrzeb, stosować bardziej wyrafinowane, jeżeli oczywiście jest to
potrzebne.
W średnich i dużych systemach narysowanie diagramu pakietów może być jedną z najbardziej
wartościowych czynności, którą można wykonać w celu skontrolowania wielkoskalowej struktury
systemu. W idealnej sytuacji diagram taki powinien zostać wygenerowany z samego kodu, tak aby
można było zobaczyć, co rzeczywiście znajduje się w systemie.
Dobra struktura pakietów charakteryzuje się przejrzystym przepływem zależności. Tę cechę
trudno zdefiniować, ale często łatwiej rozpoznać. Na rysunku pokazano przykładowy diagram
pakietów dla aplikacji przedsiębiorstwa, który ma dobrą strukturę i przejrzysty przepływ
zależności.
Często przejrzysty przepływ zależności można rozpoznać po tym, że wszystkie zależności
podążają w jednym kierunku. Mimo że jest to dobry wyznacznik, to widać na rysunku , że pakiety
warstwy odwzorowania danych nie są zgodne z tą regułą. Pakiety te stanowią warstwę izolacyjną
między pakietami domeny i bazy danych.
Im więcej zależności dochodzi do pakietu, tym stabilniejszy musi być interfejs tego pakietu,
ponieważ każda zmiana w interfejsie przeniesie się na wszystkie zależne pakiety. A zatem na
rysunku pakiet warstwy domeny aktywów musi mieć stabilniejszy interfejs niż pakiet warstwy
odwzorowania danych leasingu. Aby pakiet był bardziej stabilny powinien zawierać możliwie
dużo interfejsów i klas abstrakcyjnych (patrz slajd 25 z poprzedniego wykładu).
Relacje zależności nie są przechodnie (poprzedni wykład slajd 20). Aby dostrzec, dlaczego jest to
istotne w wypadku zależności, spójrzmy ponownie na rysunek na slajdzie. Zmiana w klasie
pakietu aktywa-domena może pociągnąć za sobą zmianę w pakiecie leasing-domena. Ale ta
zmiana niekoniecznie przeniknie do warstwy prezentacji dziedziny leasingu. (Stanie się tak tylko
wtedy, gdy dziedzina leasingu zmieni swój interfejs.)
11
Pakiet jak zbiór klas abstrakcyjnych i interfejsów
Aplikacja
Bramka
Bazy danych
Bramka
Bramka
Bramka
Oracle
SQL Server
Test Stub
Projektowanie systemów informatycznych, wykład 3
12
Zdarza się, że jeden pakiet definiuje interfejs implementowany przez kilka innych
pakietów, na przykład tak jak na zaprezentowanym rysunku. W takim wypadku relacja
implementacji wskazuje na to, że bramka bazy danych definiuje Merfejs, a inne klasy
bramek bazodanowych zapewniają implementację. W praktyce oznaczałoby to, że pakiet
bramki bazodanowej zawiera interfejsy i klasy abstrakcyjne zaimplementowane
całkowicie przez inne pakiety.
Bardzo częstą praktyką jest umieszczanie interfejsu i jego implementacji w osobnych
pakietach.
12
Przykład pakietu z interfejsem
Ogrzewanie::Grzejnik
Projektowanie systemów informatycznych, wykład 3
Oświetlenie::Lampa
13
Załóżmy, że należy zaprojektować element interfejsu użytkownika do włączania i
wyłączania różnych urządzeń. Element ten powinien współpracować z wieloma różnymi
urządzeniami, takimi jak grzejniki i światła. Musi wywoływać metodę na przykład dla
grzejnika, ale nie powinien być od niego zależny. Powstania zależności między
grzejnikiem a elementem sterującym można uniknąć, definiując w pakiecie elementu
sterującego interfejs, który następnie zostanie zaimplementowany przez dowolną klasę,
która zechce współpracować z tym elementem sterującym. Ilustruje to rysunek na
slajdzie
13
Używanie diagramów pakietów
¾
Diagramy pakietów są przydatne w dużych systemach, gdyż pozwalają na
uzyskanie obrazu zależności między głównymi elementami. Diagramy
pakietów
dobrze
odpowiadają
często
stosowanym
strukturom
programistycznym. Rysowanie diagramów pakietów i zależności pomaga w
utrzymywaniu pod kontrolą zależności występujących w aplikacji.
¾
Diagramy pakietów reprezentują mechanizm grupowania w czasie
kompilowania programu.
Projektowanie systemów informatycznych, wykład 3
14
14
Diagram stanów
Diagram stanów przedstawia maszynę stanową składającą się ze stanów, przejść,
zdarzeń i czynności. Opisuje on stany pewnego procesu, które są istotne z punktu
widzenia modelu pojęciowego tego procesu, oraz przejścia pomiędzy stanami
wymuszane poprzez wywoływane usługi obiektu. Określa też reakcje obiektu na
zdarzenia zachodzące podczas jego użycia. Diagram stanów odnosi się do
modelowania dynamicznych aspektów systemu.
Projektowanie systemów informatycznych, wykład 3
15
Zasady tworzenia diagramów stanów zaprezentowano na wykładzie dotyczącym modelowania
systemów informatycznych w poprzednim semestrze. W celu przypomnienia podstawowych
informacji dotyczących diagramów stanów proszę przeczytać odpowiedni fragment kursu
modelowania systemów informatycznych. Na niniejszym wykładzie zamierzam zaprezentować
jedynie sposoby implementacji diagramów stanów na podstawie przykładu.
Będąc studentem, a nie było to tak dawno (niestety za kilka lat to ostatnie wtrącenie będę musiał
wykreślić), namiętnie grałem w gry strategiczne typu Heroes of Might and Magic, Age of Empires,
Red Alert… . Niestety teraz nie mam już czasu na tego typu intelektualne przygody. Ponieważ
jednak darze sentymentem gry strategiczne to mój przykład będzie związany z pewnym aspektem
tego typu gier.
Załóżmy, że gramy w grę gdzie musimy rozbudowywać osadę. Pierwszym budynkiem jaki należy
zbudować aby stworzyć wioskę jest chata sołtysa. Następnie rozbudowujemy wioskę tworząc kolejne
chaty i zakłady rzemieślnicze, koszary itd. Kiedy liczba mieszkańców przekroczy 100 wtedy
możemy zlecić rozbudowanie (upgrade) chaty sołtysa do ratusza. Wydanie zlecenia rozbudowy
chaty sołtysa pod warunkiem osiągnięcia liczby 100 mieszkańców oznacza przekształcenie wioski w
miasto. Miasto rozbudowujemy dalej o nowe budynki również takie których nie mogliśmy tworzyć
we wiosce. Wydanie zlecenia rozbudowy ratusza do zamku królewskiego pod warunkiem
osiągnięcia liczby 1000 mieszkańców oznacza przekształcenie miasta w stolicę. Status stolicy
oznacza dodatkowe przywileje oraz umożliwia budowanie nowych budynków, których nie można
było budować w mieście (zwłaszcza budynki obronne). Oczywiście nasza osada może zostać
zaatakowana przez obcą armię. Wtedy może stracić status stolicy jeżeli liczba mieszkańców spadnie
poniżej 1000 lub status miasta jeżeli liczba mieszkańców spadnie poniżej 100. Jeżeli natomiast we
wiosce zostanie zburzona chata sołtysa, w mieście ratusz, a w stolicy zamek królewski to osada
przestaje istnieć. Oczywiście jest to przykład uproszczony i z punktu widzenia logiki gry można by
się do niego w kilku miejscach przyczepić. Przykład uprościłem specjalnie aby stworzyć w miarę
prosty i czytelny diagram stanów zaprezentowany na następnym slajdzie.
15
Przykład diagramu stanów
Wybud. chaty sołtysa
[odpowiednia ilość miejsca na planszy]
[lm < 100]/ Zablokowanie budowania
budynków miasta i niemożność
korzystania z bud. miasta
Zlecenie wybud. ratusza [lm ≥100]/
Możliwość budowania budynków miejskich
[lm < 1000]/Zablokowanie budowania
budynków stolicy i niemożność korzystania
z bud. stolicy
Miasto
Zburzenie
ratusza
Wioska
Zburzenie chaty
sołtysa
Zlecenie wybud. ZK [lm ≥ 1000 ]/
Możliwość budowania budynków stolicy
Legenda:
Stolica
Zburzenie ZK
ZK – zamek królewski
lm – liczba mieszkańców
Projektowanie systemów informatycznych, wykład 3
16
16
Implementacja diagramu stanów - switch
void Osada::ObslugaPrzejścia(ZdarzenieOsady Zd)
{
switch (StanAktualny){
case StanOsady.Wioska:
switch(Zd){
case ZdarzenieOsady.ZlecenieWybudRatusza:
if(lm>=100) StanAktualny = StanOsady.Miasto;
break;
case ZdarzenieOsady.ZburzenieChatySoltysa:
StanAktualny = StanOsady.Zburzona;
break;
}
break;
case StanOsadyMiasto:
switch(Zd){
case ZdarzenieOsady.ZlecenieWybudZK:
if(lm>=1000) StanAktualny = StanOsady.Stolica;
break;
case ZdarzenieOsady.ZburzenieRatusza:
StanAktualny = StanOsady.Zburzona;
break;
case StanOsadyStolica:
switch(Zd){
case ZdarzenieOsady.ZburzenieZK:
StanAktualny = StanOsady.Zburzona;
}
if(lm < 1000) StanAktualny = StanOsady.Miasto;
}// Koniec switch(StanAktualny)
}//koniec funkcji Obsluga zdarzenia
}
if(lm < 100) StanAktualny = StanOsady.Wioska;
break;
Projektowanie systemów informatycznych, wykład 3
17
Najbardziej bezpośrednim podejściem jest zaimplementowanie diagramu stanów za
pomocą zagnieżdżonej instrukcji switch. Na aktualnym slajdzie zaprezentowano
przykład takiej implementacji dla diagramu ze slajdu 16. Proszę zauważyć, że funkcja
ObsługaPrzejścia obsługuje tzw. przejścia automatyczne czyli takie, które zachodzą
automatycznie przy spełnieniu określonego warunku. Przejścia takie nie są rezultatem
generacji jakiegokolwiek zdarzenia Zd. Stąd czy funkcja będzie działać poprawnie dla
tego typu przejść? Funkcja ta będzie działać poprawnie dla przejść automatycznych
wtedy gdy będzie wywoływana przy każdym obiegu pętli komunikatów niezależnie czy
wygenerowano ZdarzenieOsady czy nie. Można również postąpić inaczej i obsługę
przejść automatycznych umieścić w osobnej funkcji, która będzie wywoływana w
każdym obiegu pętli obsługi komunikatów. Wtedy funkcję ObsługaPrzejścia będzie
można wywoływać tylko wtedy gdy wygenerowano ZdarzenieOsady.
W powyższym pseudokodzie nie uwzględniono przejścia realizowanego przez zdarzenie
wybudowania chaty sołtysa. Przejście to prowadzi od pseudostanu do stanu Wioska i jest
związane z utworzeniem obiektu klasy Osada stąd nie może być obsłużone w funkcji z
klasy Osada. Przejście to powinno być obsłużone w globalnej funkcji obsługi przejść.
Rezultatem tego przejścia będzie utworzenie obiektu klasy Osada, ustawienie jej
parametrów początkowych i dodanie obiektu do kolekcji wszystkich obiektów gry.
Proszę również zauważyć, że w niniejszym kodzie nie zaprezentowano akcji typu
odblokowania, zablokowania budowania budynków miasta lub stolicy przy
odpowiednich przejściach. Dzieje się tak dlatego, że w kodzie możliwość budowania
budynków miasta lub stolicy rozpoznaje się po stanie osady.
Mimo że podejście z instrukcją switch wydaje się najbardziej oczywiste prowadzi do
powstania długiego i nieczytelnego kodu nawet w prostych przypadkach.
17
Implementacja diagramu stanów – klasa abstrakcyjna
Kontroler
StanOsady
ZmianaStanuNa(StanOsady )
ObsZlecenieWybudRatusza(Kontroler* K)
ObsZburzenieChatySoltysa(Kontroler* K)
ObsZlecenieWybudZK(Kontroler* K)
ObsZburzenieRatusza(Kontroler* K)
ObsZburzenieZK(Kontroler* K)
ObsZdAutomatycznych()
stan 1
ObsZlecenieWybudRatusza(Kontroler* K)
ObsZburzenieChatySoltysa(Kontroler* K)
ObsZlecenieWybudZK(Kontroler* K)
ObsZburzenieRatusza(Kontroler* K)
ObsZburzenieRatusza(Kontroler* K)
ObsZburzenieZK(Kontroler* K)
ObsZdAutomatycznych(Kontroler* K)
stan->ObsZdAutomatycznych(this)
StanWioska
StanMiasto
StanStolica
ObsZlecenieWybudRatusza(Kontroler* K)
ObsZburzenieChatySoltysa(Kontroler* K)
ObsZdAutomatycznych(Kontroler* K)
ObsZlecenieWybudZK(Kontroler* K)
ObsZburzenieRatusza(Kontroler* K)
ObsZdAutomatycznych(Kontroler* K)
ObsZburzenieZK(Kontroler* K)
ObsZdAutomatycznych(Kontroler* K)
If(lm >= 100)
K->ZmianaStanuNa(StanMiasto);
Projektowanie systemów informatycznych, wykład 3
StanKoniec
If(lm < 100)
K->ZmianaStanuNa(StanWioska);
18
W metodzie ze wzorcem klasy stanów tworzy się hierarchię klas stanów do obsługi
zachowania się tych stanów. Każdy stan na diagramie ma jedną podklasę stanów.
Kontroler ma metody dla każdego zdarzenia, które po prostu powodują odesłanie do
odpowiedniej klasy stanów. Na szczycie hierarchii zdarzeń znajduje się klasa
abstrakcyjna (StanOsady), która implementuje wszystkie możliwe metody obsługi
zdarzeń tak aby nic nie robiły. Każda klasa konkretnego stanu przeciąża metody
obsługujące przejścia wychodzące z tego stanu. Powyższy przykład pokazuje diagram
klas UML, z fragmentami kodu w C++, prezentujący klasy implementacyjne diagramu
stanów ze slajdu 16.
18
Implementacja diagramu stanu – tablica stanów
Stan źródłowy Stan docelowy Zdarzenie
Dozór
Procedura
Pseudostan
Wioska
WybudChatySołtysa
Odpowiednia
ilość miejsca
na planszy
Umożliwienie rozbudowy osady
Wioska
Koniec
ZburzenieChatySoltysa
Wioska
Miasto
ZlecenieWybudRatusza
lm ≥ 100
Umożliwienie
budynków miasta
Miasto
Koniec
ZburzenieRatusza
Miasto
Wioska
lm < 100
Zablokowanie
budowania
budynków
miejskich
oraz
możliwości korzystania z nich
Miasto
Stolica
ZlecenieWybudZK
lm ≥ 1000
Umożliwienie
budynków stolicy
Stolica
Koniec
ZburzenieZK
Stolica
Miasto
lm < 1000
Zablokowanie
budowania
budynków
miejskich
oraz
możliwości korzystania z nich
Projektowanie systemów informatycznych, wykład 3
budowy
budowy
19
Tabela stanów to trzecie podejście polegające na zakodowaniu informacji z diagramu
stanów w postaci tabeli danych. Przykładowemu diagramowi ze slajdu 16 odpowiada
tabela zaprezentowana na niniejszym slajdzie. Po sporządzeniu tabeli tworzy się
interpreter, który używa tablicy stanów w czasie wykonywania programu, albo generator
kodu, który tworzy klasy na podstawie tabeli stanów.
Tabela ma taką zaletę, że może być modyfikowana bez ponownej kompilacji programu.
Wzorzec stanów jest łatwiejszy do przygotowania, gdy jest potrzebny doraźnie, chociaż
potrzeba nowej klasy dla każdego stanu, to nie ma przy tym zbyt dużo kodowania.
Niezależnie od tego jaki sposób implementacji stosujemy to zwykle w realnych
zadaniach implementacja stanów prowadzi do bardzo skomplikowanego kodu stąd
zastosowanie narzędzi CASE w postaci generatorów kodu jest tu ze wszech miar
uzasadnione.
19
Diagramy wdrożenia
Diagramy wdrożenia przedstawiają fizyczny układ systemu. Pokazują, w których
częściach sprzętu działają poszczególne fragmenty oprogramowania.
Znacznik z
wartością
Serwer aplikacji
Klient-przeglądarka
htt
p/I
nte
przeglądarka
Klient dedykowany
{OS=Windows}
ReaClient.exe
rne
t
ieć
p/s a
htt kaln
lo
Serwer WWW
{OS=Linux}
{serwer WWW = apache}
{Obsługa konta}
{liczba wdrożeń = 5}
Węzeł
urządzenia
Wdrożony
artefakt
Projektowanie systemów informatycznych, wykład 3
Zapytanie
SQL
Ścieżka
komunikacyjna
SQL server
System bazodanowy
kont klientów
Oracle
Węzeł środowiska
wykonawczego
20
Diagramy wdrożeń przygotowywane są na etapie projektowania systemu i pokazują miejsca
wdrożeń poszczególnych fragmentów systemu, więc okazują się bardzo pomocne w wypadku
dużych systemów oraz systemów rozproszonych.
Na rysunku znajduje się prosty przykład diagramu wdrożenia. Głównymi elementami diagramu są
węzły połączone za pomocą ścieżek komunikacyjnych Węzeł jest to coś, co może utrzymywać
jakąś część oprogramowania. Są dwa rodzaje węzłów. Pierwszym jest węzeł urządzenia, czyli
sprzęt. Węzeł urządzenia może reprezentować komputer albo mniej złożoną część sprzętu
komputerowego podłączoną do systemu. Drugim rodzajem jest węzeł środowiska wykonawczego.
Reprezentuje on oprogramowanie, które samo się uruchamia lub zawiera inne oprogramowanie
Przykładem może tu być system operacyjny. Węzły zawierają artefakty, czyli oprogramowanie w
fizycznej postaci — najczęściej pliki. Pliki mogą być zbiorami wykonywalnymi (na przykład .exe,
pliki binarne, biblioteki DLL, pliki JAR, asemblacje lub skrypty) lub plikami danych, plikami
konfiguracyjnymi, dokumentami HTML itp. Wpisanie artefaktu do węzła oznacza, że artefakt ten
jest wdrożony do tego węzła w działającym systemie.
Artefakty można przedstawić albo za pomocą ramek klas, albo wypisując ich nazwy w węźle. W
wypadku użycia pierwszego sposobu można dodać ikonę dokumentu lub słowo kluczowe
«artifact». Węzły lub artefakty można oznaczyć za pomocą znaczników z wartościami. W ten
sposób można podać różne interesujące informacje o węźle, takie jak producent, system
operacyjny, lokalizacja itd.
Często w systemach istnieje kilka fizycznych węzłów wykonujących to samo logiczne zadanie.
Można to pokazać za pomocą kilku ramek węzłów lub za pomocą znacznika z liczbą wdrożeń
(Przykładowo na rysunku 5 serwerów WWW).
Ścieżki komunikacyjne między węzłami ilustrują, w jaki sposób poszczególne elementy
komunikują się ze sobą. Ścieżki te można oznaczyć etykietami i zapisać w nich informacje o
użytych protokołach komunikacyjnych.
20

Podobne dokumenty