Wykład 12. Praktyczna realizacja projektu abstrakcyjnego W następującym rozdziale przyjrzymy się praktycznej realizacji przykładowego projektu informatycznego realizowanego na zamówienie. Analizie poddany zostanie projekt oraz realizacja prototypu fragmentu funkcjonalności przykładowego systemu przeznaczonego do wsparcia działalności korporacji taksówkowej. W niniejszym projekcie, dla uproszczenia przykładu założymy, że w korporacji taksówkowej występować będzie ograniczony zestaw następujących aktorów: telefonistka przyjmująca zamówienia, dyspozytor koordynujący pracę taksówkarzy, taksówkarz oraz klient. W pierwszej części, zgodnie z metodyką opisaną w rozdziale 6, przeanalizujemy cele poszczególnych aktorów. Następnie wyodrębnimy zbiór podstawowych obiektów związanych z działalnością korporacji tworząc w ten sposób słownik dziedziny. Na podstawie tych danych, które będą stanowić analizę wymagań, stworzymy dokument wymagań określając przypadki użycia systemu, scenariusze przypadków użycia oraz widoki abstrakcyjne. W kontekście podręcznika dotyczącego projektowania graficznych interfejsów użytkownika skoncentrujemy się na procesie realizacji projektów abstrakcyjnych interfejsu. W dalszej kolejności przygotujemy projekty wizualne widoków i okien na podstawie projektu abstrakcyjnego, a na samym końcu stworzymy interaktywny prototyp wykorzystując do tego celu technologię Microsoft Windows Forms. Technologia ta posłuży jako przykład obrazujący wykorzystanie możliwości narzędzia do realizacji projektu abstrakcyjnego. Skoncentrujemy się na tym jak efektywnie w Microsoft Windows Forms realizować widoki i okna przy uwzględnieniu wszystkich udokumentowanych zależności w projekcie abstrakcyjnym. Najbardziej interesującym nas procesem będzie połączenie projektu abstrakcyjnego z implementacją prototypu. 12.1 Koncepcja ogólna systemu Tworzony przykładowy system zakłada, że korporacja taksówkowa przyjmuje zamówienia telefonicznie lub za pomocą smsów. Przyjmowaniem zamówień od klientów zajmują się panie telefonistki. Zamówienia są przekazywane do dyspozytora, który za pomocą bezpośredniej komunikacji przy wykorzystaniu radia CB komunikuje się z taksówkarzami przekazując im zlecenia do realizacji. Taksówkarze za pomocą radia CB raportują do dyspozytora swój status dostępności oraz lokalizację. Korporacja planuje zinformatyzowanie procesów funkcjonujących w firmie. W ramach informatyzacji zakłada się, że powinna istnieć jedna lokalizacja która będzie umożliwiać dodawanie zleceń, śledzenie ich realizacji, raportowanie, prognozowanie zleceń, 1
ewidencjonowanie taksówkarzy, geograficzną optymalizację przydziału zleceń do taksówkarzy, ewidencjonowanie stałych klientów korporacji. Zakłada się automatyzację działań dyspozytora. Przydział taksówkarza do zlecenia powinien być możliwy przy wykorzystaniu specjalnych terminali i odbywać się bez pośrednictwa dyspozytora. Spowoduje wyeliminowanie komunikacji między dyspozytorem a taksówkarzami przy wykorzystaniu radia CB. Rola dyspozytora będzie ograniczać się do nadzorowania realizacji zleceń, śledzenia statusów taksówkarzy i reakcji na sytuacje wyjątkowe. Telefonistka powinna mieć dostęp do statusu zlecenia, statusów taksówkarzy, filtrowania taksówkarz z informacją o ich geograficznej lokalizacji. Telefonistka powinna mieć możliwość określenia minimalnego czasu jaki potrzebuje korporacja do podstawienia taksówki na zamówienie klienta. Ograniczmy nasz projekt do wymienionych powyżej założeń. Jest oczywiste, że gdybyśmy tworzyli rzeczywisty system do obsługi procesów w korporacji taksówkowej zbiór wymagań koncepcji systemu kilka razy większy. 12.2 Struktura projektu Do celów realizacji naszego projektu posłużymy się następującą strukturą. Pierwsza część projektu będzie dotyczyć analizy wymagań i projektu funkcjonalnego, które przygotujemy w narzędziu CASE. Druga część będzie stanowić statyczny prototyp wizualny, który będą stanowić szkielety widoków i stron abstrakcyjnych. Do realizacji interaktywnego prototypu wykorzystamy środowisko Microsoft Windows Form w zintegrowanym środowisku programistycznym Microsoft Visual Studio. Projekt analizy wymagań wygodnie jest podzielić tematycznie na pakiety w notacji UML. Projektu będziemy realizować w przykładowym narzędziu CASE - Enterprise Architect firmy Sparx Systems Pty Ltd [1]. Drzewo projektu zostało zaprezentowane na rysunku 12.1. Na rysunku widać model wymagań, który składa się z widoków Analiza wymagań oraz Wymagania funkcjonalne. Są to etapy zgodne z omawianą w rozdziałach 6 i 7 metodyką projektowania UCD. W ramach analizy wymagań określamy Użytkowników oraz ich Cele w ramach przedsiębiorstwa. W niniejszym rozdziale pominięto prezentację tych celi z uwagi na ich prostotę, ograniczona objętość podręcznika oraz stosunkowo niewielką rolę, ponieważ zostały wstępnie opisane w podrozdziale 12.1. Wymagania funkcjonalne składają się z Przypadków użycia uwzględniających Scenariusze, które stanowią podział zadań między użytkowników oraz system, oraz Projektu abstrakcyjnego okien oraz widoków. Po raz kolejny w naszym projekcie pominęliśmy jeden etap scenariusze biznesowe opisujące procesy w korporacji taksówkowej. Ze względu na to, że okna w naszym projekcie wygodnie jest powiązać z konkretnymi aktorami, którzy są bezpośrednio związani z przypadkami użycia, pogrupujemy właśnie po aktorach. Zaznaczmy, że nie jest rozwiązanie ogólne i nie należy go stosować do wszystkich 2
możliwych projektów. Czasami wygodniej jest zastosować inny podział. Jeżeli pojawiłby się nam problem z powtarzającymi się oknami dla różnych aktorów to powinniśmy przemyśleć projekt aktorów naszego systemu i spróbować uogólnić pewne role w naszym systemie i przedstawić je uwzględniając relację dziedziczenia. Rys. 12.1: Struktura projektu analizy wymagań zaprezentowana w narzędziu Enterprise Architect [1] 12.3 Analiza wymagań funkcjonalnych Projekt rozpoczynamy od przygotowania analizy wymagań funckjonalnych. Pierwszy etap to wyodrębnienie aktorów systemu. Pamiętajmy, że aktorzy systemu nie powinni być połączeni z fizycznymi osobami takim jak Jan Nowak, itp. Aktorzy powinni być rolami, które łączą w sobie funkcje powiązane ze sobą tematycznie. W przypadku naszej korporacji może zdarzyć się sytuacja, że w przypadku dużego obciążenia osoba pełniąca rolę dyspozytora może czasowo realizować zadania telefonistki. W naszym systemie wyróżnimy trzy główne role: dyspozytora, telefonistkę i taksówkarza. Klient, pomimo tego że występuje w koncepcji ogólnej systemu jest jedynie aktorem biznesowym i nie będzie miał bezpośredniego kontaktu z systemem, a więc nie będziemy potrzebować 3
projektować dla niego interfejsu użytkownika. Diagram aktorów został przedstawiony na rysunku 12.2. Rys. 12.2: Diagram aktorów systemu dla korporacji taksówkowej 12.4 Analiza wymagań Kolejnym etapem projektu naszego przykładowego przypadku systemu jest przygotowanie przypadków użycia. Przypadki użycia systemu powinniśmy wyodrębnić z diagramu celów użytkowników, który ze względu na prostotę naszego systemu został jednak pominięty. Posłużymy się tutaj zatem podrozdziałem ogólnej koncepcji systemu. Jak już wcześniej zostało wspomniane w przypadku systemu dla korporacji taksówkowej wygodnie jest podzielić funkcje systemu względem aktorów systemu. Na początku przyjrzymy się przypadkom użycia dla Taksówkarza, a następnie Telefonistki. Pominiemy przypadki użycia Dyspozytora, których wygląd byłby bardzo podobny do pozostałych dwóch aktorów, uwzględniając oczywiście inne zadania jakie realizuje w korporacji. W przypadku taksówkarza na początku wyodrębnimy dwa podstawowe przypadki użycia dotyczące logowania Zalogowanie w systemie oraz Wylogowanie z systemu. Przypadki te są niezbędne do realizacji wymagania ewidencjowania taksówkarzy oraz ich statusów dostępności. Po zalogowaniu taksówkarz powinien mieć możliwość realizacji przypadku Wyświetlenia dostępnych zleceń do realizacji. W przypadku, gdy zlecenie będzie odpowiadało taksówkarzowi może samodzielnie dokonać Wyboru zlecenia do realizacji. Z różnych przyczyn (np. korek, awaria samochodu, kontrola policyjna, itp.) taksówkarz musi mieć możliwość Anulowania realizacji zlecenia. Po zakończeniu realizacji powinien mieć możliwość aktualizacji statusu zlecenia poprzez Zatwierdzenie realizacji zlecenia. Taksówkarz powinien również móc Poinformować o gotowości w lokalizacji aby Telefonistka mogła poinformować o tym klienta. W trakcie oczekiwania na zlecenia z korporacji taksówkarz może zrealizować zlecenie we własnym zakresie. Na przykład w sytuacji gdy klient podchodzi do niego na postoju taksówek bez pośrednictwa korporacji. W takiej sytuacji taksówkarz musi mieć możliwość Zmiany statusu na zajęty. Po wykonaniu własnego zlecenia powinien ponownie móc zmienić swój status na wolny, bez potrzeby ponownego logowania do systemu za pomocą przypadku użycia Zmiana statusu na wolny. Wymienione przypadki użycia zostały przedstawione na rysunku 12.3. 4
Rys 12.3: Przypadki użycia systemu przez Taksówkarza W tym momencie powinniśmy utworzyć dla każdego przypadku użycia zbiór odpowiednich scenariuszy. W podręczniku pokażemy jednak jeden przykładowy. Będzie to scenariusz dla przypadku Wybór zlecenia do realizacji. Scenariusz ten przedstawimy w postaci tekstowej zgodnie z notacją Podmiot-Orzeczenie-Dopełnienie [3]: {Wymaganie: Taksówkarz jest zalogowany} 1. Taksówkarz wybiera opcję [Wyświetl listę zleceń]. 2. System wyświetla okno z [Listą zleceń]. 3. Taksówkarz wybiera opcję [Realizuj] znajdującą się przy zleceniu. 4. System wyświetla informację ze [Szczegółami zlecenia]. 5. {Alt: Anulowanie wyboru} a. Taksówkarz wybiera opcję [Anuluj]. b. System wyświetla okno z [Listą zleceń]. {Alt: Zatwierdzenie wyboru} a. Taksówkarz wybiera opcję [Zatwierdź] b. System oznacza status zlecenia na [Realizowane] c. System wyświetla okno [Realizacji zlecenia] 5
Przypominamy, że w powyższym scenariuszu, dla wygody i późniejszego wykorzystania oznaczyliśmy słowa i zwroty, które będą nam potrzebne w dalszej części projektu. Elementy te staną się zazwyczaj oknami lub widokami abstrakcyjnymi, lub ich operacjami i atrybutami. Dla przykładu okno wyświetlające widok [Szczegóły zlecenia] na pewno będzie musiało mieć przyciski [Anuluj] i [Zatwierdź]. W projekcie abstrakcyjnym konfigurację tą zamodelujemy za pomocą klasy OknoSzczegółyZlecenia, która będzie składać się z klasy WidokSzczegółyZlecenia i zawierać operacje anuluj() i zatwerdź(). Pozostawiając ten pojedynczy przykład scenariusza przejdźmy do przypadków użycia telefonistki. Rys. 12.4: Diagram przypadków użycia telefonistki Kolejnym etapem przygotowywania wymagań funkcjonalnych jest zbudowanie słownika dziedziny i określenie relacji między pojęciami. Słownik ten posłuży nam do zbudowania listy widoków, które będziemy musieli zaprojektować i zrealizować w naszym systemie. Każdy obiekt z dziedziny użytkownika będzie musiał być zaprezentowany poszczególnym użytkownikom systemu. Obiekty będą prezentowane za pomocą widoków. Zbiory widoków poszczególnych 6
obiektów będą zgromadzone w oknach. Relacje pomiędzy obiektami pomogą nam określić jakie widoki powinny składać się z innych widoków, jakie powinny być zrealizowane nawigacje pomiędzy widokami oraz które obiekty widoki będą najważniejsze z punktu widzenia systemu i będą koniecznie musiały być zrealizowane w prototypie. Przypomnijmy sobie, że w rozdziale dotyczącym prototypowania zaprezentowaliśmy koncepcję, w której prototyp powinniśmy rozpoczynać od najważniejszych widoków. Diagram obiektów z relacjami pozwoli nam takie obiekty z projektu wyodrębnić. Na rysunku 12.5 przedstawiony został diagram klas reprezentujący zależności pomiędzy podstawowymi obiektami występującymi w systemie dla korporacji taksówkowej. Podkreślmy po raz kolejny, że diagram ten jest, do celów podręcznika uproszczony i nie zawiera wszystkich rzeczywistych obiektów i relacji. Rys. 12.5: Diagram klas reprezentujący słownik pojęć związanych z działalnością korporacji taksówkowej Na diagramie klas obrazującym pojęcia z dziedziny użytkownika kończymy dokument analizy wymagań. W kolejnych etapach przejdziemy do projektu funkcjonalnego interfejsu rozpoczynając od uszczegółowienia diagramu pojęć o atrybuty i operacje, które będziemy wykorzystywać przy tworzeniu projektu abstrakcyjnego funkcjonalności interfejsu użytkownika. 7
12.5 Projekt abstrakcyjny Kolejnym etapem projektu jest przygotowanie formalnej specyfikacji funkcjonalnej wymagań systemu, a w kontekście naszego podręcznika interfejsu użytkownika. Zakładając, że posiadamy ogólny diagram pojęć zaprezentowany na rysunku 12.5 możemy spróbować uściślić ten diagram uzupełniając go o operacje na pojęciach oraz ich atrybuty. Przypominamy, że źródłem tych informacji powinny być udokumentowane cele użytkowników systemu, przypadki użycia oraz scenariusze. Przykład scenariusza zamieszczony został w poprzednim podrozdziale i przedstawiał przypadek użycia wyboru zlecenia do realizacji przez taksówkarza. Na rysunku 12.6 przedstawiony został uzupełniony diagram pojęć. Aby pokazać przykładowe źródła poszczególnych szczegółów diagramu pojęć umieszczony został również diagram przypadków użycia taksówkarza. Strzałki pokazane na diagramie pokazują źródło pochodzenia poszczególnych szczegółów diagramu pojęć. Rys. 12.6: Diagram szczegółowego słownika pojęć z zaznaczonymi przykładowymi odniesieniami do diagramu przypadków użycia Na diagramie przypadków użycia z rysunku 12.6 w prawym dolnym rogu widzimy notatkę o treści Zmiana [statusu] [zlecenia] na [zrealizowane]. Notatka ta wskazuje nam, że obiekt Zlecenie musi posiadać pole, które będzie przechowywać informację o statusie czyli musi mieć atrybut 8
status. Zależność tą zaznaczyliśmy na rysunku za pomocą strzałki od notatki do atrybutu status obiektu Zlecenie. Jako typ statusu, dla uproszczenia, wybieramy String czyli ciąg znaków. W profesjonalnej aplikacji na pewno powinien to być jakiś osobny typ danych, najlepiej klasa. Kolejny przykład wiąże się z przypadkiem użycia o nazwie Wybór [zlecenia] do [realizacji]. Przypadek ten wskazuje, że zlecenie powinno umożliwiać wykonanie pewnej operacji, która spowoduje podjęcie realizacji konkretnego zlecenia. Na diagramie zamodelowaliśmy to za pomocą operacji o nazwie realizuj() i zdefiniowanej w obiekcie Zlecenie. Jako samodzielne ćwiczenie spróbuj teraz odnaleźć uzasadnienie dla pozostałych przedstawionych na diagramie strzałek. Załóżmy, że nasz diagram obiektów użytkownika, przedstawiony na rysunku 12.6 jest kompletny. Przejdziemy teraz do najważniejszej części z punktu widzenia podręcznika projektu abstrakcyjnego funkcjonalności interfejsu użytkownika. Na początku zdefiniujemy widoki abstrakcyjne poszczególnych obiektów, następnie stworzymy modele szablonów okien dla poszczególnych aktorów, a na końcu pokażemy kilka modeli przykładowych okien. Proces ten został przedstawiony schematycznie na diagramie na rysunku 12.7. Rys. 12.7: Schemat procesu wytwarzania projektu abstrakcyjnego funkcjonalności Dla przypomnienia widok jest to jednostka wizualna, która grupuje logicznie związaną funkcjonalność w jednym elemencie wizualnym, który najczęściej jest prostokątem. Widoki na etapie projektowania służą do uogólniania szczegółowej funkcjonalność w większe grupy. Do grupowania można wykorzystać metodę sortowania kart. Stworzone na etapie projektowani widoki pomagają w: ujednoliceniu wyglądu oraz sposobów interakcji tych samych obiektów w ramach całego projektu, ponownemu wykorzystaniu komponentów w ramach systemu, koncentracji na logicznym układzie strony lub formularza na etapie projektowania układów widoków. Tworząc modele widoków poszczególnych obiektów staramy się przewidzieć jakie widoki danych obiektów będą nam potrzebne. Jeden obiekt może być prezentowany różnym 9
użytkownikom systemu w różny sposób. Zwróćmy uwagę na stwierdzenie w różny sposób. Przypominamy, że na obecnym etapie projektu nie zajmujemy się tym jaka będzie graficzna prezentacja danego obiektu lecz, które informacje i jakie operacje powinny się w danym widoku znaleźć. To jest, podkreślmy główna zasada tworzenia projektu abstrakcyjnego, który jest niezależny od prezentacji. Oczywiście ten samo obiekt może również pojawiać się temu samemu użytkownikowi w różny sposób w zależności od kontekstu w którym występuje. Co określa na obecnym etapie projektu ten kontekst? Kontekst powinien wynikać z konkretnego scenariusza przypadku użycia. Na przykład, dyspozytor przeglądając listę zleceń do realizacji i potrzebując informacji która telefonistka zarejestrowała to zlecenie widzi widok szczegółów telefonistki w innym kontekście niż telefonistka swój widok w scenariuszu w którym modyfikuje swoje hasło dostępowe do systemu. Dlatego potrzebne są dwa osobne widoki, które zaprezentowane na rysunku 12.8: TelefonistkaSzczegóły w kontekście informacji o telefonistce, która zarejestrowała zlecenie oraz TelefonistkaProfil w kontekście modyfikacji hasła przez samą telefonistkę. Rys. 12.8 Diagram widoków obiektu telefonistki abstrakcyjny model reprezentujący widoki, które będą wyświetlać informację o telefonistce Oprócz tych dwóch widoków przewidujemy widok TelefonistkaPanel, który nie jest związany bezpośrednio z funkcjami biznesowymi systemu, ale są konieczne z technologicznego punktu widzenia. Panel ten jest typowym widokiem aktualnie zalogowanego użytkownika. 10
Czwartym widokiem jest widok TelefonistkaInfo, który będzie wykorzystywany w widokach raportów i tabelach gdzie będziemy potrzebować zwartej prezentacji danych. Kolejnym obiektem, dla którego zaprojektujemy widoki jest Zlecenie. Zlecenie realizowane przez korporację taksówkową jest niewątpliwie najważniejszym obiektem systemu. Diagram widoków, nawet w przypadku naszego uproszczonego modelu systemu, zawiera aż osiem widoków. Rys. 12.9: Widoki zlecenia abstrakcyjna prezentacji widoków, które będą prezentować w systemie zlecenia Poszczególne widoki wynikają ze scenariuszy przypadków użycia telefonistki oraz taksówkarza: 1. PodgladZlecenia ze scenariusza przypadku użycia taksówkarza: Wyświetlenie [dostępnych] [zleceń] 2. EdycjaZlecenia ze scenariusza przypadku użycia telefonistki: Rejestracja zlecenia 11
3. ListaZlecenTelefonistka wykorzystywany w wielu scenariuszach przydatków użycia telefonistki (np. Przegląd [zleceń], Przegląd [statusu] [zlecenia], Anulowanie zlecenia ) 4. ZlecenieWRealizacji widok ze scenariusza przypadku użycia taksówkarza Wybór [zlecenia] do [realizacji] Zwróćmy uwagę, że pod względem dostępnych funkcji stworzyliśmy uogólniony widok ListaZlecen, który jest rozszerzany dla telefonistki i taksówkarza. Widoki te są ze sobą powiązane pod względem funkcjonalnym i będą mogły być zaimplementowane zachowując tą zależność. Zależność tą należy jednak na etapie implementacji traktować jako wskazówkę, a nie wymaganie. Może okazać się, że widoki telefonistki są realizowane w innej technologii niż interfejs taksówkarza. Wtedy implementacje będą oczywiście niezależne. W przypadku opracowywane w ramach tego rozdziału prototypu obie aplikacje będą napisanej na tej samej platformie, a więc ta zależność idealnie zredukuje liczbę komponentów w projekcie. Kolejnym obiektem, który będzie prezentowany w interfejsie użytkownika jest lokalizacja. Na rysunku 12.10 przedstawiony został model widoków abstrakcyjnych dla tego obiektu. Jak widać, przewidujemy dwie reprezentacje lokalizacji: EdycjaLokalizacji widok wykorzystywany w scenariuszu telefonistki w którym rejestruje ona nowe zlecenie oraz LokalizacjaInfo wykorzystywany w scenariuszu taksówkarza dotyczącym przypadku użycia Wybór zlecenia do realizacji. Rys. 12.10: Model widoków abstrakcyjnych obiektu lokalizacja W każdym projekcie interfejsu oprócz widoków związanych z dziedziną dla której tworzona jest aplikacja potrzebne są widoki technologiczne związane z użyciem systemu. Są to widoki systemowe. W naszej aplikacji pokażemy jeden, przykładowy widok, który będzie elementem 12
szablonu każdej strony telefonistki i będzie stanowić menu z operacjami dostępnymi dla telefonistki z dowolnego miejsca aplikacji. Widok ten nazwiemy MenuTelefonistki. Na rysunku 12.11 zaprezentowany został model widoku MenuTelefonistki, który zawiera operacje reprezentujące funkcje, które powinny być dla telefonistki dostępne z dowolnego miejsca systemu. Zgodnie z diagramem przewidujemy operacje: dodawania zlecenia, przejścia do ekranu głównego, przycisku uruchamiającego przypadek użycia Wyznaczenie [minimalne czasu] podstawienia [taksówki], przypadek użycia Obejrzenie [lokalizacji] na planie miasta, oraz przypadku Filtracja [zleceń]. Rys. 12.11 Przykładowy widok systemowy niezwiązany z dziedziną aplikacji związany z obsługą samego interfejsu użytkownika służący do w tym przypadku wyłącznie do nawigacji Na tym zakończymy przykłady modeli abstrakcyjnych widoków obiektów pozostawiając czytelnikowi jako ćwiczenie przygotowanie widoków dla Taksówkarza, Dyspozytora, Kontaktu i PlanuMiasta. W następnej kolejności, zgodnie z diagramem na rysunku 12.7, zajmiemy się przygotowaniem szablonów widoków, które będą wspólne dla wszystkich okien poszczególnych aktorów systemu. Rys. 12.12: Model abstrakcyjny szablonu wszystkich okien telefonistki 13
Ze względu na ograniczony rozmiar podręcznika oraz zupełną analogię przedstawimy przykład modelu abstrakcyjnego szablonu okna telefonistki, a następnie pokażemy jak wykorzystując go zamodelować specyficzne okna. Model abstrakcyjny szablonu okna telefonistki umieścimy w oddzielnym pakiecie Wspólne widoki GUI, który będzie zawierać widoki wykorzystywane w całej aplikacji. SzablonOknaTelefonistki składa się z widoku TelefonistkaPanel reprezentującego status zalogowania oraz MenuTelefonistki czyli menu udostępniającego funkcje uruchamiania poszczególnych przypadków użycia przewidzianych dla telefonistki. Zwróćmy uwagę, że zależność opisana jako składa się z została zamodelowana za pomocą relacji agregacji. Agregacja oznacza w tym przypadku, że komponenty te mogą istnieć samodzielnie nie są związane z samym szablonem, który jest dla nich kontenerem. Należy zaznaczyć, że w tym konkretnym przypadku jest to jedynie konwencja i swobodnie mogliśmy do opisu tej relacji zastosować kompozycję. Na obecnym etapie projektu nie ma to większego znaczenia. Dysponując szablonem okna telefonistki możemy przejść do trzeciej fazy przygotowywania projektu abstrakcyjnego którym, zgodnie z rysunkiem 12.7 są Okna. Rys. 12.13: Model abstrakcyjny okna powitalnego telefonistki prezentujący rozszerzenie szablonu okna telefonistki oraz to, że składa się z ListyZlecenTelefonistki 14
Na rysunku 12.13 przedstawiony został model okna powitalnego telefonistki. To do niego powinna prowadzić operacja ekranglowny() zdefiniowana w MenuTelefonistki oraz to OknoPowitalne, zgodnie ze swoja nazwą powinno wyświetlać się telefonistce po zalogowaniu do systemu. OknoPowitalne telefonistki rozszerza SzablonOknaTelefonistki, co zostało zamodelowane za pomocą relacji dziedziczenia. W notacji UML strzałka pomiędzy OknemPowitalnym a SzablonemOknaTelefonistki oznacza, że OknoPowitalne dziedziczy z szablonu wszystkie cechy. Dodatkowo w modelu wykorzystaliśmy relację kompozycji oznaczającej, że OknoPowitalne składa się z ListyZlecenTelefonistki. Wykorzystana relacja kompozycji uściśla nam tutaj, że ListaZlecenTelefonistki jest nierozerwalnie związana z OknemPowitalnym i w tym kontekście przestaje istnieć razem z oknem telefonistki. Tego typu uszczegółowienie stanowi podpowiedź dla osoby przygotowującej implementację informując, że instancja widoku może być zaszyta bezpośrednio w oknie. Jakie mogłoby być inne rozwiązanie? Na przykład moglibyśmy mieć w ramach całej aplikacji, aby zaoszczędzić pamięć operacyjną, kontener przechowujący instancje wszystkich widoków i wykorzystywać je podczas generowania widoków. Takie rozwiązanie wymagałoby relacji agregacji zamiast kompozycji. Zauważmy jednak, że tego typu analiza jest bardzo trudna do przeprowadzenia na etapie projektów abstrakcyjnych w oderwaniu od technologii i jest stosunkowo rzadko stosowana. Rys. 12.13: Model abstrakcyjny okna powitalnego telefonistki z mniej restrykcyjną relacją pomiędzy OknemPowitalnym i ListaZlecenTelefonistki 15
W praktyce więc, diagram okna telefonistki powinien zawierać relację agregacji i pozostawiać osobie implementującej dowolność dotyczącą określenia czasu życia i dokładnego związku między OknemPowitalnym a ListaZlecentelefonistki. Poprawiony diagram zaprezentowany został na rysunku 12.14. Projekty abstrakcyjne okien rzadko przygotowywane są w oderwaniu od wizualnych projektów szkieletów okien (ang. wireframes). Trzeba mieć duże doświadczenie i wyćwiczoną wyobraźnię aby móc przygotować je bez naszkicowania sobie tych okien. Dlatego na rysunku 12.14a przedstawiony został szkielet wizualny dla szablonu okien telefonistki, a obok na rysunku 12.14b szkielet wizualny okna powitalnego telefonistki. a) b) Rys. 12.14: Wizualne projekty a) szablonu stron telefonistki oraz b) przykładowego okna powitalnego Aby zaoszczędzić miejsce w praktycznej dokumentacji praktycznie nigdy na diagramach prezentujących modele abstrakcyjnych okien nie pokazuje się elementów z których składa się szablon. Na rysunku 12.15 pokazano model okna nowego zlecenia, który występuje w scenariuszu przypadku użycia telefonistki Rejestracja [zlecenia]. Diagram zawiera informację, że OknoNowegoZlecenia rozszerza (relacja dziedziczenia) SzablonOknaTelefonistki oraz składa się z widoku EdycjiZlecenia. 16
Rys. 12.15: Okno nowego zlecenia telefonistki 12.6 Projekty widoków wizualnych Prototyp Przejdziemy teraz realizacji prototypu wizualnego naszego systemu. Prototyp zrealizujemy wykorzystując technologię formularzy Microsoft Windows Forms [2]. W technologii tej programista może tworzyć własne kontrolki za pomocą: kontrolek złożonych (ang. Composite Controls), które często są nazywane kontrolkami użytkownika (ang. User Controls), kontrolki te stanowią kontener przechowujący inne kontrolki oraz informacje o nich; w ten sposób tworzymy kontrolkę składającą się z innych kontrolek i możemy ją współdzielić w wielu miejscach aplikacji, kontrolek rozszerzających (ang. Extended Controls), które rozszerzają funkcjonalność standardowych kontrolek takich jak np. Button, o dodatkowe możliwości; kontrolki tego typu tworzymy, gdy chcemy rozszerzyć funkcjonalność nie zmieniając wyglądu wizualnego lub odwrotnie, gdy chcemy zrealizować nowy wygląd wizualny pozostawiając funkcjonalność niezmienioną, własnych kontrolek (ang. Custom Controls), które dziedziczą bezpośrednio z uogólnionej klasy kontrolki Control; musimy wtedy stworzyć odpowiednie metody generujące widok oraz obsługujące komunikaty. Oprócz kontrolek użytkownika środowisko Microsoft Visual Studio umożliwia pełne dziedziczenie projektu wizualnego oraz kodu zawartego w formularzach. Innymi słowy, nowe formularze możemy stworzyć na podstawie już istniejących rozszerzając je. Funkcja ta odpowiada 17
relacji dziedziczenia, która wykorzystaliśmy w modelu abstrakcyjnym na przykład na rysunku 12.13. Rys. 12.16: Okno nowego zlecenia telefonistki Jak widać na rysunku 12.16 środowisko Microsoft Visual Studio.NET umożliwia tworzenie formularzy, które dziedziczą projekt z już istniejących (ang. Inherited Form). W przypadku kontrolek istnieje możliwość utworzenia nowej kontrolki złożonej (ang. User Control), nowej kontrolki dziedziczącej projekt wizualny i funkcje z już istniejącej (ang. Inherited User Control) oraz własnej kontrolki (ang. Custom Control). Z punktu widzenia naszego projektu najbardziej interesujące są kontrolki użytkownika, które służą do grupowania kontrolek oraz informacji o ich wizualnej konfiguracji. Kontrolki te doskonale pasują do opisanej metodyki w której koncentrujemy się na wyspecyfikowaniu znacznej liczby widoków abstrakcyjnych, ponieważ pomagają technicznie realizować te widoki. Dzięki temu widoki mogą być wielokrotnie wykorzystywane w dowolnym miejscu aplikacji. Należy zaznaczyć, że kontrolki użytkownika nie są cechą charakterystyczną środowiska Microsoft Visual Studio występują po różnymi postaciami również w innych technologiach, odpowiedzialnych z implementację interfejsu użytkownika. W języku Java, w technologii Java Swing, są to wszystkie komponenty rozszerzającej komponent JPanel. W technologiach internetowych, ponieważ język znaczników HTML posiada strukturę drzewiastą widoki są zazwyczaj zwykłymi gałęziami znaczników, które są osadzane na stronie. Jako znacznik kontener wykorzystywany jest zazwyczaj div, który za można swobodnie pozycjonować za pomocą arkusza stylów CSS. 18
Rys. 12.17 Struktura projektu w środowisku Microsoft Visual Studio.NET Na rysunku 12.17 zaprezentowana została przykładowa struktura projektu w Microsoft Visual Studio. Aby uprościć analizę na rysunku przedstawione zostały tylko elementy projektu, które obrazujemy jako przykłady w podręczniku. Wzorzec projektowy, który będziemy stosować dla realizacji naszego prototypu to Model-Prezenter. W skład projektu wchodzi zatem warstwa prezentacji, która obsługuje wszystkie funkcje prezentacji oraz kontrolera aplikacji, oraz warstwa modelu danych. Model danych znajduje się w folderze o tej samej nazwie, a warstwa prezentacji została pogrupowana pod kątem rodzajów obiektów, które przechowuje. W projekcie znajdują się zatem alfabetycznie: okna, szablony okien oraz widoki. Przypominamy, że widoki zostaną zrealizowane za pomocą kontrolek użytkownika, a szablon okna będzie zwykłym formularzem, którego projekt wizualny i kod będziemy dziedziczyć w specyficznych oknach poszczególnych przypadków użycia. Procedurę implementacji przykładowych widoków rozpoczniemy od przygotowania kontrolek użytkownika (User Controls) dla widoków szablonu okien telefonistki, MenuTelefonistki oraz TelefonistkaPanel. Implementację realizujemy na podstawie modelu abstrakcyjnego widoków. Na rysunku 12.18 przedstawiona została implementacja widoku TelefonistkaPanel, który składa się z etykiety oraz dwóch przycisków Zaloguj i Wyloguj reprezentujących odpowiednie operacje z modelu abstrakcyjnego. Etykieta aktualnie pokazuje wartość (nie zalogowany) i przeznaczona jest na wyświetlenie imienia i nazwiska zalogowanej telefonistki. 19
Kolejną implementacją na rysunku 12.18 jest kontrolka użytkownika realizująca widok MenuTelefonistki. Kontrolka ta zawiera pięć przycisków (Button), które reprezentują odpowiednie operacje z modelu abstrakcyjnego widoku. Rys. 12.18: Implementacje widoków w szablonie okna telefonistki za pomocą kontrolek użytkownika w środowisku Microsoft Visual Studio.NET Przykładowa implementacja kodu MenuTelefonistki została przedstawiona poniżej. Pokazujemy przykładową implementację metody cmdekranglowny(). Po raz kolejny zwróćmy szczególną uwagę na zastosowanie odpowiedniego nazewnictwa metod, które powinno być zgodne z projektem abstrakcyjnym. W tej banalnej implementacji prototypu w linii 23 kodu za każdym razem tworzymy nową instancję formularza OknaPowitalnego i wywołujemy metodę Show(), która wyświetla go na ekranie. Do celów naszego interaktywnego prototypu implementacja ta jest w zupełności wystarczająca. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; namespace KorporacjaTaksówkowa { public partial class MenuTelefonistki : UserControl 20
12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. } { } ( ) public MenuTelefonistki() { InitializeComponent(); } private void cmdekranglowny_click(object sender, EventArgs e) { new OknoPowitalne().Show(); } private void cmddodajzlecenie_click(object sender, EventArgs e) { } ( ) Listing 12.1: Przykładowy kod implementacji widoku MenuTelefonistki Na koniec zajmiemy się formularzem o nazwie SzablonEkranuTelefonistki, który implementuje szablon abstrakcyjny o tej samej nazwie. Zwróćmy szczególną uwagę na zastosowane odpowiedniego nazewnictwa, które jest niezmiernie ważne aby uzyskać spójność między modelem abstrakcyjnym i implementacją systemu. Czy na zaprezentowanym przykładzie nazwa implementacji jest prawidłowa? Oczywiście, że nie - SzablonEkranuTelefonistki powinien nazywać się SzablonOknaTelefonistki. Implementacja szablonu okna telefonistki składa się z dwóch kontrolek użytkownika, które zostały rozmieszczone zgodnie z szkieletem wizualnym z wcześniejszego etapu, a dokładnie z rysunku 12.14a. Teraz zajmiemy się widokami listy zleceń dla telefonistki. Zgodnie z modelem abstrakcyjnym z rysunku 12.9 w projekcie występują trzy widoki listy zleceń: 1. ListaZlecen zawierająca wspólne elementy pozostałych dwóch widoków, która zaimplementujemy za pomocą kontrolki użytkownika (User Control) 2. ListaZlecenTelefonistka rozszerzająca widok ListyZlecen o operacje charakterystyczne dla scenariuszy przypadków użycia telefonistki 3. ListaZlecenTaksowkarz rozszerzajaca widok ListyZlecen o operacje charakterystyczne dla scenariuszy przypadków użycia taksówkarza (ten widok pominiemy w naszym przykładowym projekcie) Na rysunku 12.19 przedstawione zostały dwie implementacje: wspólnego widoku ListaZlecen oraz widoku telefonistki ListaZlecenTelefonistka. Oba widoki zostały zaimplementowane za pomocą kontrolek użytkownika. ListaZlecenTelefonistka rozszerza widok ListaZlecen i jest rozszerzona o odpowiednie przyciski reprezentujące operacje znajdujące się w modelu widoku: anuluj(), dodaj(), powiadomionyklient(), przydzieltaksówkarza() i usun(). 21
Rys. 12.19: Implementacje widoku ogólnego listy zleceń oraz specyficznego dla scenariuszy przypadków użycia telefonistki - ListaZelecenTelefonistka Na zakończenie pokażemy przykładową implementację okna powitalnego telefonistki, która została zrealizowana za pomocą komponentu Form. Formularz został utworzony za pomocą opcji Inherited Form przedstawionej na rysunku 12.16. Następnie jako rozszerzany formularz wybrany został SzablonEkranuTelefonistki. Po wyborze tym otrzymaliśmy nowe okno, które odziedziczyło po szablonie projekt wizualny oraz kod. Elementy odziedziczone z szablonu są zablokowane do edycji w oknie dziedziczącym. Aby dokonać zmian w nich należy wykonać je bezpośrednio w szablonie. Po utworzeniu nasz formularz OkanPowitalnego wygląda tak jak na rysunku 12.18. Niczym nie różni się od samego szablonu. Jest jednak gotowy na rozszerzenie i implementację cech specyficznych dla okna powitalnego. Na rysunku 12.20 zaprezentowany został zrealizowany widok okna powitalnego w naszym formularzu. Za pomocą strzałek pokazane zostało pochodzenie poszczególnych elementów formularza. Fragmenty odziedziczone z szablonu okna telefonistki to TelefonistkaPanel, MenuTelefonistki oraz ich układ na stronie. W przypadku okna powitalnego rozszerzeniem szablonu jest umieszczenie kontrolki użytkownika realizującej widok ListaZlecenTelefonistka z rysunku 12.19 zgodnie z zaprojektowanym szkieletem wizualnym z rysunku 12.14b. 22
Rys. 12.20: Implementacja przykładowego okna telefonistki OknoPowitalne, którego projekt wizualny rozszerza SzablonOknaTelefonistki 12.7 Podsumowanie Celem niniejszego rozdziału było zilustrowanie pełnego procesu specyfikowania wymagań biznesowych, funkcjonalnych, tworzenia modelu abstrakcyjnego interfejsu użytkownika oraz jego praktycznej implementacji w wybranym środowisku Microsoft Visual Studio.NET. Na wstępie rozdziału opisaliśmy założenia praktycznego przykładu systemu wspomagającego funkcjonowanie korporacji taksówkowej. Koncepcja ogólna wymagań została następnie wykorzystana do przygotowania fragmentu specyfikacji wymagań funkcjonalnych, która objęła diagramy aktorów, przypadków użycia oraz model pojęć obiektów dziedziny aplikacji. Następnie, pomijając model biznesowy, który zazwyczaj uwzględnia dokumentację procesów zachodzących w danym przedsiębiorstwie w oderwaniu od systemu informatycznego, przeszliśmy do przygotowaniu modelu abstrakcyjnego interfejsu użytkownika. Elementami tego modelu zostały widoki obiektów z modelu pojęć, szablony okien użytkowników oraz projekty abstrakcyjne okien. Model abstrakcyjny zrealizowaliśmy wykorzystując UML i stosując notację zgodną z diagramem klas, która została opisana w rozdziale 7 podręcznika. 23
Trzecia część rozdziału dotyczy praktycznej implementacji interfejsu użytkownika w ścisłym związku z opracowanym modelem abstrakcyjnym. Do tego celu wykorzystaliśmy środowisko Microsoft Visual Studio.NET, w którym skoncentrowaliśmy się na prezentacji wykorzystania kontrolek użytkownika (User Controls). Rozdział zakończyliśmy przykładami implementacji fragmentu systemu podkreślając konieczność zachowania spójności pomiędzy poszczególnymi etapami projektu. Podkreślmy, że wygodna realizacja widoków abstrakcyjnych i dziedziczenia projektu wizualnego (ang. visual inheritance) jest podstawą praktycznie wszystkich współczesnych środowisk programistycznych, co szczególnie widać na rysunku 12.16 na którym zaprezentowano szablony komponentów, które można utworzyć w środowisku Microsoft Visual Studio.NET. Bibliografia: [1] Sparx Systems Pty Ltd, Enteprise Architect User Guide, http://www.sparxsystems.com.au/bin/eauserguide.pdf, 2010 [2] Julian Templeman, David Vitter, Visual Studio.NET:.NET Framework. Czarna księga, Helion 2003 [3] Michał Śmiałek, Zrozumieć UML 2.0. Metody modelowania obiektowego, Helion, 2005, stron 304 24