Pytanie z tytułu zna chyba każdy, dopiero zaczynający swoją naukę programowania, człowiek. Napisało się już trochę kodu, chce się dodać do niego kolejne “funkcjonalności”, ma się już nawet kod i absolutnie brak pomysłów, gdzie powinno się go umieścić. Kuba może potwierdzić, że ostatnio najczęściej zadawanym przeze mnie pytaniem było: ale gdzie to napisać? Po przeczytaniu tutorialu oracle (jako, że jestem trochę dalej niż lekcje na blogu nie mogę korzystać z tych pisanych przez Kubę), zapoznaniu się z zadaniem i napisaniu /wyszukaniu na stackoverflow rozwiązania miałam zazwyczaj dość sporą niepewność gdzie to wszystko umieścić. Czasami pomagała odpowiedź na pytania: Co to ma robić? Z czym?, ale gdy liczba linii kodu rosła, te dwa pytania coraz częściej nie wystarczały. Na odsiecz przyszły diagramy UMLowe, o których poczytasz poniżej.
UML czyli Unified Modeling Language
Służy do opisywania — modelowania fragmentu istniejącej rzeczywistości (np. działu w firmie, jakiegoś procesu czy wycinka systemu), albo projektowania i analizy czegoś, co dopiero ma powstać — np. systemów informatycznych. Nieodłącznym jego elementem są diagramy i to właśnie o jednym z nich będzie ten wpis. Jeśli jesteś bardziej zainteresowana samym UMLem to odsyłam chociażby do Wikipedii.
Activity Diagram
Czyli po polsku diagram czynności lub aktywności służy do przedstawienia krok po kroku jakie czynności są wykonywane. Nie opisuje szczegółów jak te czynności są wykonywane a jedynie pokazuje w jakiej kolejności i kiedy. Dzięki swojej budowie pokazuje, jakie są akcje, a także jak są one połączone (co w przełożeniu na pytanie z tytułu pozwala nam dokładnie ułożyć nasze fragmenty kodu w odpowiedniej kolejności). W dalszej części będziemy korzystać z podstawowych elementów diagramu:
- zaokrąglonych prostokątów reprezentujących akcje
- prostokątów reprezentujących obiekty
- rombów reprezentujących decyzje
- belek reprezentujących rozwidlenia i łączenia działań jednoczesnych
- czarne kółko reprezentujące początek (zainicjowanie)
- czarne kółko w białym kole reprezentujące koniec (stan końcowy)
Oczywiście, może się okazać, że w Twoim przypadku potrzebujesz innego elementu diagramu, opisy innych elementów znajdziesz w sekcji materiały dodatkowe. Przykładowy diagram aktywności znajduje się poniżej (jakże znany ze stron www naszych wykładowców).
W tym miejscu jeszcze parę słów, które Kuba kazał mi napisać i podkreślić: UML (jak i dowolne inne metodyki) są po to, żeby pomóc nam w projekcie. W sytuacji kiedy chcemy dodać dodatkową informację, notację itp, dodajmy ją, niezależnie od tego czy jest zgodna ze standardem czy nie. UML to wspólny język dla wielu osób, co ma ogromne znaczenie w projektach przy których pracują setki osób. W mniejszych projektach najwazniejsze żeby wszyscy członkowie zespołu rozumieli diagram i informacje w nim zawarte. Jeśli trudno wyrazić Ci intencje w standardowym UML, a wszyscy zainteresowani rozumieją wprowadzone przez Ciebie zmiany i odstępstwa, nie krępuj się. UML ma pomóc Tobie i w razie potrzeby dopasowac sie do Ciebie, a nie Ty do UMLa.
Activity diagram w praktyce
Ponieważ najłatwiej omawiać coś na przykładzie, przejdźmy do modelowania naszego wycinka rzeczywistości :) Zostawiliśmy ostatnio naszego kota pod opieką znajomego i troszkę mu się przybrało między przednimi a tylnimy łapkami. Naszym zadaniem będzie stworzenie aplikacji, która będzie chronić lodówkę przed Teslą. Aplikacja ma zapytać użytkownika o imię, i jeśli podane imię to Tesla, ma wyświetlić pouczenie o diecie, w przeciwnym wypadku wyświetlić hasło do lodówki (przyjmijmy, że to takie odrobinę zmodyfikowane “hello world”, z którym na pewno już się spotkałaś). Pierwszym krokiem w stworzeniu activity diagramu jest wypisanie wszystkich czynności, które musimy wykonać w naszym programie:
- wczytanie imienia użytkownika
- sprawdzenie, czy to nie Tesla
- wyświetlenie “jesteś na diecie”
- wyświetlenie hasła do lodówki
Następnie sprawdzamy, w których czynnościach pojawiają się jakieś obiekty/dane na wejściu lub wyjściu. Poprzez dane rozumiemy dowolną informację — np. aby wczytać imię użytkownika nie potrzebujemy żadnej informacji (nie mamy nic na ‘wejściu’), ale akcja ta daje nam ciąg znaków — imię — na wyjściu. Z kolei sprawdzenie, czy to nie Tesla, wymaga na wejściu ciągu znaków — imienia — a na wyjściu daje nam informację prawda/fałsz (flagę), czy to faktycznie Tesla. Podsumowując:
- Wczytanie imienia nie ma nic na wejściu, natomiast na wyjściu ma obiekt String imię.
- Sprawdzenie czy to Tesla, ma na wejściu String imię, a na wyjściu boolean (tak/nie).
- W przypadku tak, wyświetlamy “jesteś na diecie”,
- w przypadku nie hasło do lodówki
Takie rozpisanie naszej aplikacji ułatwia ułożenie poszczególnych elementów, bo dostrzegamy zależności pomiędzy nimi. Na podstawie tego opisu konstruujemy nasz diagram aktywności. Ważne jest to, by wszystkie obiekty czy dane były w odpowiednich miejscach. Przeanalizujmy go krok po kroku, dodając poszczególne elementy kodu: Wczytaj imię to aktywność, która pyta użytkownika o imię. Nie zawiera żadnych danych wejściowych, ale na wyjściu ma daną w postaci String imię. (metoda getUserInput() to nasza funkcja, która po prostu zwraca linijkę wpisaną przez użytkownika).
System.out.println("Cześć jak masz na imię?");
userInput = getUserInput();
Tej danej potrzebujemy do sprawdzenia czy to Tesla. W bloku decyzyjnym String imię to dana wejściowa, a daną wyjściową jest boolean (flaga tak/nie).
if (userInput.equalsIgnoreCase("Tesla"))
{
//tutaj powinien być fragment kodu jeśli użytkownik to Tesla
} else {
//tutaj powinien być fragment kodu jeśli użytkownik nie jest Teslą.
}
W zależności od wyniku testu, nasz program wyświetli hasło do lodówki albo pouczenie o diecie.
System.out.println("SuperTajneHasloDoLodowki"); //akcja do wykonania jeśli to nie Tesla
System.out.println("Jesteś na diecie"); // akcja do wykonania, jeśli to Tesla
W rezultacie nasz fragment kodu wygląda następująco:
System.out.println("Cześć jak masz na imię?");
userInput = getUserInput();
if (userInput.equalsIgnorcase("Tesla") {
System.out.println("Jesteś na diecie");
} else {
System.out.println("SuperTajneHasloDoLodowki");
}
Oczywiście nie jest to działający kod, poniżej pełny kod całej klasy (aplikacji):
import java.util.Scanner;
public class Lodowka {
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
String userInput = "";
System.out.println("Cześć jak masz na imię?");
userInput = getUserInput();
if (userInput.equalsIgnorCase("Tesla")) {
System.out.println("Jesteś na diecie");
} else {
System.out.println("SuperTajneHasloDoLodowki");
}
}
public static String getUserInput() {
return sc.nextLine().trim();
}
}
Metodę tą można również stosować dla istniejącego kodu, gdy chcemy dodać do niego nowy element. Bardzo fajną metodą nauki jest pisanie odpowiednich fragmentów kodu na post-itach /w Wordzie /notatniku i następnie przeklejanie ich w odpowiedniej kolejności na kartce papieru. Dzięki temu, po ułożeniu naszych karteczek w odpowiedniej kolejności wystarczy właściwie przepisać kod bezpośrednio do naszego programu.
Budowanie diagramu dla problemu krok po kroku
Prześledźmy zatem, jak zbudować taki diagram krok po kroku, na nieco bardziej skomplikowanym przykładzie. Najpierw określmy sobie problem. Niech będzie nim konwerter walut — wczytujemy od użytkownika kurs waluty, ilość waluty a następnie wyświetlamy użytkownikowi obliczoną wartość.
Krok 1 — wypisanie elementów które mamy (elementy wymagane)
W naszym przypadku jest to:
- wczytaj kurs (brak danych na wejściu, na wyjściu: kurs)
- wczytaj ilość (in: -, out: ilość)
- oraz oblicz (in: ilość, kurs, out: wartość).
Należy jednak pamiętać, że informacje pobierane od użytkownika są zawsze na początku zapisywane jako String. Będziemy wiec musieli zamienić je na format liczbowy ( o którym było mowa w lekcji #01), co powoduje, że mamy jeszcze:
- zamień kurs na f. liczbowy (in: String kurs, out: f.liczbowy kurs)
- zamień ilość na f. liczbowy (in: String ilość, out: f.liczbowy ilość)
Krok 2 — wypisanie elementów które będziemy potrzebowali lub dla których znamy kod (elementy opcjonalne)
Aby wczytać kurs i ilość korzystamy z metody getUserInput() (która była omówiona w lekcji #02). Aby dokonać konwersji String na f.liczbowy (zastanów się, jaki format powinien mieć kurs, a jaki ilość) korzystamy w odpowiedniej metody, tu może pomóc Stackoverflow (dla ilości: String2Integer albo dla kursu: String2Float) Odpowiednie fragmenty kodu zapisujemy sobie gdzieś “pod ręką”.
Krok 3 — konstruowanie diagramu
Są dwa główne podejścia do konstruowania takiego diagramu — od początku i od końca. W pierwszym podejściu zaczynamy od początku, czyli od sytuacji w której nie mamy żadnych danych i wykonujemy wszystkie czynności które możemy, powtarzając ten krok za każdym razem gdy otrzymamy nową informację aż otrzymamy informację, którą oczekujemy. Jest to podejście ‘zachłanne’ — tzn. robimy wszystko co możemy, dopóki nie trafimy na to, co potrzebujemy. Drugie podejście odwraca ten proces — zaczynamy od informacji którą potrzebujemy, wykonując czynności, które są potrzebne do jej otrzymania. Powtarzamy to dopóty, dopóki nie będziemy potrzebowali żadnej dodatkowej informacji. Wynik w obu przypadkach powinien być zbliżony lub identyczny (w prostszych przypadkach). Żaden z tych sposobów nie jest lepszy od drugiego, są po prostu inne. W zależności od problemu i naszej wiedzy, jeden z nich może okazać się bardziej efektywny, ale warto znać i przećwiczyć oba.
Krok 3.1 — budowa diagramu ‘od początku’
Zaczynamy od akcji, które nie potrzebują żadnych danych na wejściu. W naszym przypadku są to wczytanie kursu i wczytanie ilości. Nie ma żadnej różnicy, co zrobimy najpierw, dlatego na diagramie przedstawiamy je równocześnie.
Widzimy, że po przejściu tych akcji mamy do dyspozycji dane typu String. Jak wynika z naszej wcześniejszej analizy, możemy ich użyć do konwersji na odpowiedni format liczbowy. I to właśnie będą nasze kolejne akcje.
W ten sposób mamy już wszystkie niezbędne dane w odpowiednim formacie, by dokonać obliczeń. Wstawiamy więc akcję oblicz.
W ten sposób wykorzystaliśmy wszystkie “cegiełki”, a wyjściowa dana jest tym, czego potrzebowaliśmy. Oznacza to, że nasz wykres doszedł do punktu końcowego. Gotowy wykres wygląda tak, jak poniżej:
Krok 3.2 — budowa diagramu ‘od końca’
Zaczynając od końca, patrzymy, co ma być wynikiem naszego programu i szukamy odpowiedniej akcji, która nam go zapewni. Widzimy, że aby otrzymać Float wartość musimy dokonać akcji oblicz. Potrzebuje ona dwóch danych na wejściu, o czym wiemy z treści zadania, w odpowiednich formatach liczbowych.
Potrzebujemy teraz źródeł naszych danych. Widzimy, że możemy je uzyskać tylko poprzez wykonanie konwersji String –> f. liczbowy. To nasz drugi krok.
Widzimy, że aby dokonać konwersji potrzebujemy danych w formacie String, które pochodzą od użytkownika. To są nasze kolejne akcje.
Znów doszliśmy do punktu, w którym wszystkie elementy zostały wykorzystane, a akcje znajdujące się na górze naszego diagramu nie posiadają żadnych danych wejściowych. To znak, że możemy zakończyć (a właściwie rozpocząć) nasz diagram.
Krok 4 — przepisujemy kod
Mamy już gotowy diagram i wg niego układamy nasze fragmenty kodu. Oczywiście należy pamiętać o standardowej konstrukcji programu w Javie (o tym znajdziesz informacje w lekcji #02). Akcje, które są zapisane jako równoległe na diagramie w kodzie będą oczywiście następować po sobie, jednak nie ma znaczenia, która z nich będzie wpisana jako pierwsza.
Zadanie
Najlepiej uczyć się w praktyce, dlatego polecam stworzyć diagram aktywności do prostego programu. Stwórz program do witania się z użytkownikiem. Użytkownik podaje swoje imię i nazwisko, a program go wita. Jeśli imię użytkownika kończy się na a to słowami: Cześć, wydaje mi się, że jesteś kobietą, jeśli na inną literę to: Cześć, wydaje mi się, że jesteś mężczyzną.
Podpowiedź
Mam nadzieję, że dzięki temu wpisowi, tak jak ja, znacznie ograniczysz stres spowodowany niezbyt dużą wprawą w pisaniu w Javie (czy jakimkolwiek innym języku, bo przecież to narzędzie absolutnie uniwersalne) i łatwiej Ci będzie ułożyć swój program. A może masz inne pomysły co może pomóc w takich momentach zastoju nad kodem? Z chęcią poczytam(y) o nich w komentarzach.
PS. A jeśli wpis się podobał, to zapraszam do śledzenia fanpage’a, by być zawsze na bieżąco z naszymi postami.