Polsko-Japońska Wyższa Szkoła Technik Komputerowych Warszawa Diagramy interakcji (współpracy i sekwencji) Tomasz Górski Jakub Fogiel Bartosz Czech
Diagramy interakcji Diagramy interakcji, stanowiące jeden z rodzajów diagramów dynamicznych, pozwalają na utworzenie opisu interakcji obiektów systemu podczas realizacji danego zadania: przypadku użycia czy jednego konkretnego scenariusza danego przypadku użycia. Nie dla wszystkich przypadków użycia może zachodzić potrzeba konstruowania diagramów interakcji, ale mogą okazać się szczególnie użyteczne np. do komunkacji wewnątrz zespołu projektowego (jak zresztą wszystkie rodzaje diagramów) czy też do rozważenia opcjonalnych realizacji w “trudnych przypadkach”. Ponadto, niektóre narzędzia CASE potrafią wykorzystać te diagramy do generacji kodu, co może stanowić ważny powód dla ich konstruowania. UML posiada dwa rodzaje diagramów interakcji: diagramy współpracy (kolaboracji) diagramy sekwencji. Oba rodzaje diagramów, bazując na danym diagramie klas, pokazują prawie tą samą informację, w nieco inny sposób. Niektóre narzędzia CASE potrafią generować jedne z tych diagramów z drugich. Decyzja, który rodzaj diagramów konstruować, zależy od pożądanego aspektu interakcji.
Diagramy współpracy; przykład Diagramy współpracy pokazują w jaki sposób system realizuje dany przypadek użycia. Współpracujące obiekty, połączone “linkami”, stanowią rodzaj “kolektywu”, zwanego tu kolaboracją. Linki odpowiadają powiązaniom, czyli wystąpieniom asocjacji z diagramu klas, a to oznacza, że odpowiednia asocjacja musi istnieć na diagramie klas. inicjator Na diagramie współpracy może pojawiać się informacja taka, jak na diagramie klas, np.: :Egzemplarz książki :Książka :Personel bibl. kierunek nawigowania, nazwy linków, itp. pod warunkiem, że zwiększy, a nie zmniejszy czytelność diagramu. :Członek bibl. Prosty diagram współpracy, bez uwidaczniania interakcji między obiektami, stanowi coś w rodzaju “wystąpienia fragmentu diagramu klas”; pokazuje aktora, relewantne obiekty i powiązania między nimi. Możliwe jest pokazanie więcej niż jednego obiektu danej klasy.
Interakcja na diagramach współpracy (1) Diagramy współpracy mogą dodatkowo pokazywać interakcje zachodzące między obiektami zaangażowanymi w realizację danego przypadku użycia. Sekwencja interakacji oznacza tu sekwencję komunikatów przesyłanych między współpracującymi obiektami. komunikat wysyłany od aktora do obiektu klasy Członek bibl. (z reguły nie numerowany) :Książka :Personel bibl. 3: ZaznaczWypożyczenie Pożycz (egzemplarz) :Członek bibl. :Egzemplarz książki 2: Pożycz 1: CzyMożnaPożyczyć Komunikaty przedstawiane są tu w postaci etykiet strzałek rysowanych wzdłuż linków między współpracującymi przy realizacji przypadku użycia obiektami.
Interakcja na diagramach współpracy (2) Na diagramach współpracy nie pokazuje się odpowiedzi na wysyłane komunikaty. Komunikaty mogą być numerowane, albo kolejnymi liczbami naturalnymi (jak na poprzednim diagramie), albo stosując tzw. numerację zagnieżdżoną. :Egzemplarz książki :Książka :Personel bibl. 2.1: ZaznaczWypożyczenie Pożycz (egzemplarz) :Członek bibl. 2: Pożycz 1: CzyMożnaPożyczyć Numeracja zagnieżdżona, oznacza, że jeśli obiekt O otrzyma komunikat o numerze np. n to ten numer będzie dołączany jako prefix do każdego komunikatu wysyłanego w trakcie realizacji komunikatu n przez O.
Podsumowując Diagramy współpracy Opisują współpracę/interakcję między obiektami w wybranym kontekście Teoretycznie opisujemy tą samą systuację co przy pomocy diagramu sekwencji, ale z innej perspektywy (struktury klas) Brak osi czasu, możemy ją zastąpić numerując komunikaty Z drugiej strony mamy dzięki temu większą swobodę, uwaga skupia się na obiektach i wymianie komunikatów między nimi, a nie chronologii ich wysyłania Obiekty komunikujące się muszą być z sobą w związku asocjacji Mając diagram klas nanosimy obiekty danych klas z ich związkami i dodajemy komunikaty „na związku” Komunikat to również wywołanie metody, więc klasy współpracujących obiektów muszą zawierać metody, które będą wywoływane
Diagramy sekwencji Diagramy sekwencji nie pokazują linków między współpracującymi obiektami, można to wydedukować w oparciu o wysyłane komunikaty. :Członek bibl. :Egzemplarz książki :Książka :Personel bibl. linia życia obiektu Pożycz (egzemplarz) czas 1: CzyMożnaPożyczyć Kolejność obiektów jest bez znaczenia, ale warto zadbać o czytelność diagramu. aktywne życie obiektu 2: Pożycz 2.1: ZaznaczWypożyczenie
Nakładanie ograniczeń na przepływ czasu (1) :Członek bibl. :Egzemplarz książki :Książka :Personel bibl. gdy interesuje nas czas potrzebny na przesłanie komunikatu A Pożycz (egzemplarz) 1: CzyMożnaPożyczyć {C-A < 5 sek.} { ZaznaczWypożyczenie - Pożycz < 1 sek.} 2: Pożycz 2.1: ZaznaczWypożyczenie c Dwa sposoby opisywania czasu: oznaczanie skali czasowej lub nakładanie ograniczeń na upływ czasu.
Tworzenie i usuwanie obiektów (1) Czasami przydaje się uwidocznienie wartości zwracanej przez komunikat, poprzez instrukcję przypisania. Umożliwia to późniejsze wykorzystanie tej wartości, np. jako argumentu dla innego komunikatu. Może też być wykorzystana do specyfikowania warunku czy iteracji. :Wykładowca nowy obiekt pojawia się na diagramie w miejscu korespondującym z czasem jego utworzenia :Sekretariat ds. nauczania n := PobierzNazwisko Wykładowca UtwórzNowegoSzefaWykładowców (n) :Szef wykładowców usuń X Szef wykładowców koniec życia obiektu
Tworzenie i usuwanie obiektów (2) 1: n := PobierzNazwisko :Sekretariat ds. nauczania :Wykładowca {usuwany} 3: usuń 2: UtwórzNowegoSzefaWykładowców (n) własność :Szef wykładowców {nowy} Komunikaty wysyłane od aktora są w tym wypadku numerowane, aby możliwe było ustalenie ich wzajemnej kolejności. Musi być wyspecyfikowane, kto jest odpowiedzialny za usuwanie obiektów, aby zapobiec “wyciekaniu pamięci”. Niektóre języki, takie jak np.Java czy SmallTalk, posiadają wbudowane mechanizmy zbierania nieużytków (garbage collectors). Z grubsza, polega to na usuwaniu (w jakimś czasie) wszystkich obiektów, do których nie ma żadnych referencji w systemie.
Generyczne diagramy interakcji (1) W UML, generyczny diagram interakcji ma specyfikować wszystkie możliwe sekwencje interakcji dla danego przypadku użycia, a nie tylko dla jednego z prawdopodobnych scenariuszy. Diagram dla pojedynczego scenariusza jest nazywany wystąpieniem generycznego diagramu interakcji. Przedstawianie zachowań warunkowych Wysłanie komunikatu może być uzależnione od spełnienia wyspecyfikowanego warunku. 1 2 ten sam punkt w czasie dwa różne punkty w czasie :K [i = 0] x [i = 1] y :K jeśli i zostanie zmienione w międzyczasie [i = 0] x {warunki muszą się wykluczać dla interakcji sekwencyjnej} [i = 1] y W zależności od wartości i oba komunikaty x i y mogą być wysłane. Może być wysłany albo komunikat x albo y. Może też nie być wysłany żaden z nich.
Generyczne diagramy interakcji (2) Warunek, zapisany wewnątrz nawiasów [ ] stanowi wyrażenie typu Boolean i może być wyrażony w języku naturalnym, w języku ustrukturalizowanym (np. OCL), w języku programowania czy innej notacji. :K1 :K2 Linia życia dla wystąpienia klasy K2 uległa rozgałęzieniu, aby podkreślić fakt, że stan obiektu może wyglądać inaczej w zależności od tego, który komunikat zostanie odebrany. 7.1: [i = 0] x 7.2: [i = 1] y Budzi wątpliwości numeracja komunikatów, ponieważ dla interakcji sekwencyjnej może zostać wysłany tylko jednen z nich. Być może oba powinny być oznaczone przez 7.1.
Generyczne diagramy interakcji (3) Wyrażanie warunków na diagramach współpracy jest także możliwe,ale bez ilustrowania rozgałęzienia linii życia obiektu. Wydaje się, że poza najprostszymi sytuacjami, diagramy sekwencyjne lepiej modelują realizację bardziej złożonych (z opcjonalnymi scenariuszami) przypadków użycia. Przedstawianie iteracji UML umożliwia oznaczenie komunikatu, który ma być wysłany wiele razy, poprzez poprzedzenie symbolem * warunku określającego zakończenie iteracji. Przykłady iteracji: *[i := 1..10] - komunikat będzie wysłany 10 razy, *[x < 10] - komunikat będzie wysyłany dopóki x będzie < 10, *[pozycja znaleziona] - komunikat będzie wysyłany do momentu, gdy pozycja nie zostanie znaleziona (gdy warunek przyjmie wartość FALSE) Jeśli w trakcie wielokrotnego wysyłania komunikatu x, będzie wysyłany także komunikat y, to zostanie on wysłany tyle razy, ile razy wysyłane jest x. Zachowanie spójności diagramów nie wymaga powtarzania symbolu iteracji dla komunikatu y.
Generyczne diagramy interakcji (4) 1 :K1 :K2 :K3 3.1: *[i := 1..2] x 3.1.1: y xyxy 2 :K1 :K2 :K3 xyyyxyyy 3.1: *[i := 1..2] x 3.1.1: *[j := 1..3] y sekwencja komunikatów
Implementacja import java.util.*; String nazwisko; public class Klient { String imie; LinkedList wypozyczone; public static void main(String[] args) Film f = new Film("Przeminęło z wiatrem"); Klient k = new Klient("Jan","Kowlalski"); { Nosnik n = new Nosnik("DVD",f); } k.wypozycz(f); public Klient(String imie,String nazwisko) this.nazwisko = nazwisko; this.imie = imie; wypozyczone = new LinkedList(); public void zwroc(Film f) wypozyczone.remove(f); public void wypozycz(Film f) f.wypozycz(this); if(czyMoznaWypozyczyc() && f.czyFilmDostepny()) public boolean czyMoznaWypozyczyc() } return wypozyczone.size() > 3; public class Kaseta { String typ; boolean wypozyczony; Film f; { public Kaseta(String typ,Film f) f.egzemplarze.add(this); this.f = f; this.typ = typ; } wypozyczony = false; public void wypozycz(Klient k) k.wypozyczone.add(this); wypozyczony = true; public void zwroc() public Klient(String imie,String nazwisko) import java.util.*; public class Klient { LinkedList wypozyczone; Film f = new Film("Przeminęło z wiatrem"); String nazwisko; Klient k = new Klient("Jan","Kowlalski"); public static void main(String[] args) if(czyMoznaWypozyczyc() && f.czyFilmDostepny()) wypozyczone = new LinkedList(); String imie; Nosnik n = new Nosnik("DVD",f); this.nazwisko = nazwisko; this.imie = imie; k.wypozycz(f); public void zwroc(Film f) wypozyczone.remove(f); public boolean czyMoznaWypozyczyc() public void wypozycz(Film f) { } return wypozyczone.size() > 3; f.wypozycz(this); } Implementacja
LinkedList wypozyczone; public static void main(String[] args) import java.util.*; public class Klient { String nazwisko; String imie; LinkedList wypozyczone; public static void main(String[] args) { Klient k = new Klient("Jan","Kowlalski"); Film f = new Film("Przeminęło z wiatrem"); Nosnik n = new Nosnik("DVD",f); k.wypozycz(f); } public Klient(String imie,String nazwisko) this.imie = imie; this.nazwisko = nazwisko; wypozyczone = new LinkedList(); public void zwroc(Film f) wypozyczone.remove(f); public void wypozycz(Film f) if(czyMoznaWypozyczyc() && f.czyFilmDostepny()) f.wypozycz(this); public boolean czyMoznaWypozyczyc() return wypozyczone.size() > 3; } import java.util.*; public class Film { String tytul; LinkedList egzemplarze; public Film(String tytul) { this.tytul = tytul; egzemplarze = new LinkedList(); } public boolean czyFilmDostepny() Iterator i = egzemplarze.iterator(); while(i.hasNext()){ Kaseta kaseta = (Kaseta)i.next() if(kaseta.wypozyczony) return true; return false; public void wypozycz(Klient k) Kaseta n = (Kaseta)i.next(); if(!n.wypozyczony) n.wypozycz(k); public class Kaseta { String typ; Film f; boolean wypozyczony; public Kaseta(String typ,Film f) { this.typ = typ; this.f = f; f.egzemplarze.add(this); wypozyczony = false; } public void wypozycz(Klient k) wypozyczony = true; k.wypozyczone.add(this); public void zwroc()
public void zwroc(Film f) import java.util.*; public class Klient { String nazwisko; String imie; LinkedList wypozyczone; public static void main(String[] args) { Klient k = new Klient("Jan","Kowlalski"); Film f = new Film("Przeminęło z wiatrem"); Nosnik n = new Nosnik("DVD",f); k.wypozycz(f); } public Klient(String imie,String nazwisko) this.imie = imie; this.nazwisko = nazwisko; wypozyczone = new LinkedList(); public void zwroc(Film f) wypozyczone.remove(f); public void wypozycz(Film f) if(czyMoznaWypozyczyc() && f.czyDostepny()) f.wypozycz(this); public boolean czyMoznaWypozyczyc() return wypozyczone.size() > 3; } import java.util.*; public class Film { String tytul; LinkedList egzemplarze; public Film(String tytul) { this.tytul = tytul; egzemplarze = new LinkedList(); } public boolean czyFilmDostepny() Iterator i = egzemplarze.iterator(); while(i.hasNext()){ Kaseta kaseta = (Kaseta)i.next() if(kaseta.wypozyczony) return true; return false; public void wypozycz(Klient k) Kaseta n = (Kaseta)i.next(); if(!n.wypozyczony) n.wypozycz(k); public class Kaseta { String typ; Film f; boolean wypozyczony; public Kaseta(String typ,Film f) { this.typ = typ; this.f = f; f.egzemplarze.add(this); wypozyczony = false; } public void wypozycz(Klient k) wypozyczony = true; k.wypozyczone.add(this); public void zwroc()
:Klient :Kaseta :Klient :Film Wypozyc(Film) 3.1: wypozycz(Klient) 1: czyMoznaWypozyczyc() :Film 2: czyFilmDostepny() 3: wypozycz(Klient)
Dziekujemy za Uwagę Koniec