PO Obiektowe modelowanie dziedziny

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania

Wprowadzenie

Programowanie obiektowe (ang. object-oriented programming) jest obecnie najpopularniejszą techniką tworzenia programów komputerowych. Program komputerowy wyraża się się jako zbiór obiektów będących bytami łączącymi stan (czyli dane) i zachowanie (czyli metody, które są procedurami operującymi na danych obiektu). W celu realizacji zadania obiekty wywołują nawzajem swoje metody zlecając tym samym innym obiektom odpowiedzialność za pewne czynności. W porównaniu z tradycyjnym programowaniem proceduralnym, w którym dane i procedury nie są ze sobą związane, programowanie obiektowe ułatwia tworzenie dużych systemów, współpracę wielu programistów i ponowne wykorzystywanie istniejącego kodu.

Historia programowania obiektowego

Pierwszy język obiektowy – Simula 67 – powstał już w latach sześćdziesiątych ubiegłego stulecia. Jego twórcami byli Ole-Johan Dahl i Kristen Nygaard z Norsk Regnesentral w Oslo. Podczas swoich prac nad symulacją statków musieli dla każdego rodzaju statku uwzględniać wiele atrybutów. Ponieważ liczba modelowanych rodzai statków była duża, uwzględnienie wszystkich możliwych zależności między atrybutami stało się problematyczne. Pojawił się pomysł, aby pogrupować różne rodzaje statków w klasy obiektów. Każda klasa obiektów sama miała być odpowiedzialna za definiowanie swoich danych i zachowania. Simula była pierwszym językiem programowania, w którym wprowadzono pojęcie klasy i jej egzemplarza. Warto tu zwrócić uwagę, że zgodnie z nazwą języka takie odwzorowanie obiektów spotykanych w świecie rzeczywistym na obiekty programowe można nazwać symulacją.

Nie długo potem w laboratorium badawczy Xerox's Palo Alto stworzono Smalltalk. Jego głównym pomysłodawcom był Alan Kay. Smalltalk zawierał wiele rewolucyjnych pomysłów w tym dziedziczenie i zyskał sobie sporą popularność. W pewnej skali był również z powodzeniem stosowany w praktyce. Standardem przemysłowym programowanie obiektowe stało się jednak dopiero w latach dziewięćdziesiątych za sprawą języka C++, który jest obiektowym rozszerzeniem C. Obecnie najpopularniejszym językiem obiektowym i równocześnie najpopularniejszym językiem programowania w ogóle jest Java.

Znajomość języka obiektowego takiego jak Java jest niezbędna, aby zostać programistom obiektowym, jednak zgodnie z powiedzeniem "posiadanie młotka nie czyni architektem" zanim przyjrzymy się konstrukcjom spotykanym w obiektowych językach programowania wyjaśnijmy kilka pojęć i nauczmy się tego co najważniejsze, czyli co to znaczy myśleć obiektowo.

Czemu programowanie obiektowe stało się takie popularne?

Największym atutem programowania obiektowego jest zbliżenie programów komputerowych do naszego sposobu postrzegania rzeczywistości. Często nazywa się to zmniejszeniem luki reprezentacji (ang. representational gap). Wymyślając nowy lub analizując istniejący program obiektowy nasz mózg ma ułatwione zadanie. Dlatego ludzie są w stanie łatwiej zapanować nad kodem i tym samym tworzyć większe programy. Łatwiej jest również zrozumieć kod i pomysły innych programistów i tym samym współpracować w zespole oraz ponownie wykorzystywać istniejące rozwiązania. Co więcej ten sam, naturalny dla ludzi sposób myślenia i te same pojęcia można użyć przy analizie problemu który ma być rozwiązany i projektowaniu jego programowego rozwiązania. Zauważmy, że już Arystoteles analizując rzeczywistość wprowadził pojęcia formy i materii. Formie w programowaniu obiektowym odpowiada Klasa, materii jej egzemplarz wymiennie nazywany obiektem. Klasyfikacja, czyli łączenie występujących w rzeczywistości obiektów w grupy --- klasy, jest najbardziej naturalnym sposobem rozumienia rzeczywistości.

Analiza i projektowanie obiektowe

Z programowaniem obiektowym nieodzownie wiążą się analiza i projektowanie obiektowe (ang. Object-Oriented Analysis and Design, OOA/D). Analiza to badanie problemu i wymagań, ale nie rozwiązania. Analiza to obszerny termin. Analiza obiektowa (ang. object-oriented analisys) zajmuje się odnajdywaniem i badaniem obiektów pojęciowych. Obiekty pojęciowe nie mają nic wspólnego z programowaniem. Reprezentują pojęcia i koncepcje ze świata rzeczywistego, a dokładniej z dziedziny, która jest analizowana. W wypadku systemu informacyjnego dla Zakładu Transportu Miejskiego, obiektami pojęciowymi są na przykład: Autobus, Linia i Kierowca.

Projektowanie to wymyślanie koncepcyjnego rozwiązania (programistycznego i sprzętowego), które realizuje wymagania. Takim koncepcyjnym rozwiązaniem może być opis schematu bazy danych lub obiektów programowych. Podczas projektowania zazwyczaj pomija się niskopoziomowe lub oczywiste (dla zamierzonych odbiorców projektu) szczegóły i koncentruje się na wysokopoziomowych pomysłach oraz ideach. Projektowanie obiektów programowych określane jest jako projektowanie obiektowe (ang. object-oriented design).

Najważniejszą czynnościom projektowania obiektowego jest wyznaczenie odpowiedzialności obiektom programowym oraz określenie jak mają współpracować, by wykonać zadanie. Tak naprawdę są to jedyne czynność jakie na pewno trzeba będzie wykonać. Główna trudność polega na tym że istniej wiele poziomów swobody, a każde rozwiązanie ma swoje wady i zalety. Na programowaniu obiektowym nauczysz się na co zwracać uwagę i jak świadomie wybierać. Poznasz również wzorce projektowe, czyli typowe rozwiązania typowych problemów, których wady i zalety dobrze poznano.

Analiza i projektowanie dają się krótko streścić jako "zrób co należy (analiza) i zrób to jak należy (projektowanie)".

Proces wytwórczy

Należy tu podkreślić, że w większości przedsięwzięć programistycznych nie da się najpierw wykonać całej analizy, potem przygotować kompletnego projekt, a na końcu jedynie przekształcić go w kod. Takie podejście nazywane "kaskadowym" opiera się na błędnych przekonaniach, że wytwarzanie oprogramowania jest podobne do innych zajęć, np. budowania domów. Tak nie jest. Większość przedsięwzięć programistycznych to opracowywanie nowego produktu, gdzie nawet klient nie wie dokładnie czego chce. Najlepiej wytwarzać oprogramowanie przyrostowo, dzieląc całą pracę na krótkie, trwające od dwóch do sześciu tygodni iteracje. W każdej iteracji wykonuję się zarówno analizę, projektowanie jak i pisze kod. Oczywiście w początkowych iteracjach więcej czasu będzie poświęcane jest na analizę, a w końcowych na projektowanie i kodowanie. Wynikiem każdej iteracji powinien być sprawny system posiadający jedynie część funkcjonalności. Zmiany będą się pojawiały i trzeba się z nimi pogodzić, ale można ograniczyć ich zasię i koszt wybierając do realizacji w początkowych iteracjach wymagania, które mają największą wartość dla klienta, których realizacja wywiera największy wpływ na architekturę systemu i które niosą za sobą największe ryzyko. W ten sposób zmniejsza się prawdopodobieństwo zmian, które powodują zmarnowanie części już wykonanej pracy.

Więcej o procesach wytwórczych i tworzeniu iteracyjnym dowiesz się na Inżynierii oprogramowania !!! link !!! Mimo, że w tej chwili ta rada może wydawać ci się na wyrost i prawdopodobnie nie możesz się już doczekać poznawania obiektowych języków programowania zapamiętaj: pisząc program zaliczeniowy z programowania obiektowego oraz w przyszłej pracy zawodowej nie odraczaj trudnych i ryzykownych zagadnień na sam koniec!

Obiektowe modelowanie dziedziny

Zgodnie ze swoją nazwą model dziedziny ma odzwierciedlać pojęcia z modelowanej części świata rzeczywistego oraz ich zależności. Jest to najważniejszy artefakt analizy obiektowej. W modelu dziedziny nie zajmujemy się obiektami programowymi. Może on posłużyć jako źródło inspiracji prze ich projektowaniu, ale nie myślmy na razie o programowaniu. Tworzenie modelu dziedziny nie jest obowiązkowe ale bardzo przydatne, jeżeli dziedzina problemu, który rozwiązujemy nie jest dobrze zrozumiała. Jeżeli jest, tworzenie modelu dziedziny należy potraktować jako dekompozycję dziedziny na godne uwagi pojęcia i obiekty. Inspirowanie się nim podczas projektowania systemu pomoże w zmniejszeniu luki reprezentacji.

W modelu dziedziny pokazuję się:

  • klasy pojęciowe
  • powiązania między klasami pojęciowymi
  • atrybuty klas pojęciowych

Przykład częściowego model dziedziny dla aplikacji wspomagającej rezerwację miejsc i sprzedaż biletów kinowych znajduje się na poniższym diagramie.

Przykład częściowego model dziedziny dla aplikacji wspomagającej rezerwację miejsc i sprzedaż biletów kinowych

Klasy pojęciowe przedstawione są w prostokątach. Są to Film, Seans i Sala. Ich nazwy przyjęło się umieszczać w pierwszej przegródce prostokąta i pisać wielką literą. Jeżeli nazwa klasy składa się z kilku członów, łączy się je i każdy kolejny człon również rozpoczyna wielką literą, np. RozkładJazdy. Ciągłe linie między klasami to powiązania. Przy pomocy powiązań pokazuje się, że między egzemplarzami klas pojęciowych może zachodzić związek, który warto pamiętać przez jakiś czas. Powiązania również mają nazwy. Będziemy je zapisywać tak samo jak nazwy klas pojęciowych, chociaż niektórzy nazwy członów rozdzielają myślnikami. Jako nazw powiązań należy używać zwrotów czasownikowych tak, aby informacje na diagramie tworzyły zdania. W naszym przypadku z diagramu można odczytać: film jest wyświetlany w trakcie seansu oraz seans odbywa się w sali. Domyślnie przyjmuje się kierunek czytania z-góry-na-dół lub od-lewej-do-prawej. Jeżeli niewygodnie jest rozmieścić klasy na diagramie, żeby zachować domyślny kierunek czytania można przy etykiecie umieścić jakiś symbol graficzny wskazujący właściwy kierunek czytania, np. wypełniony na czarno trójkącik. W drugiej przegródce prostokąta reprezentującego klasę pojęciową umieszcza się jej atrybuty, na przykład egzemplarze Filmu posiadają tytuł i czasTrwania.

Jak tworzyć modele dziedziny wyjaśnimy na przykładzie gry w Monopol.

Odnajdywanie klas pojęciowych

Przy znajdywaniu klas pojęciowych (ang. conceptual class) należy postępować jak kartograf:

  • należy używać istniejących nazw, np. gdy analizujesz system do zbierania wyników w nauce, który ma być używany w liceum, jego użytkownikami będą uczniowie, gdy jest przeznaczony dla uczelni wyższe to studenci
  • nie zajmuj się niczym co nie dotyczy części rzeczywistości, którą modelujesz; jeżeli pracujesz iteracyjnie powstrzymaj się od rozpoznawania klas pojęciowych, które są nieistotne w obecnej iteracji
  • nie dodawaj rzeczy, których nie ma

Przy odnajdywaniu klas pojęciowych posłużymy się listą często spotykanych kategorii klas pojęciowych.

Często spotykane kategorie klas pojęciowych
Kategoria Przykłady Klasy z dziedziny gry w Monopol
transakcje SprzedażBiletu, RezerwacjaMiejsc
pozycje transakcji PozycjaRezerwacji
produkty bądź usługi związane z transakcjami i kontraktami lub ich pozycjami Bilet
gdzie transakcje są odnotowywane Kasa, WykazDostępnychMiejsc
role ludzi i organizacji związanych z transakcją Kasjer Gracz
miejsce zajścia transakcji/obsługi transakcji Kasa, SalaKinowa
zdarzenia (często trzeba pamiętać czas ich zajścia) Seans GraWMonopol
obiekty fizyczne Bilet, Kino, Kasa, Miejsce Plansza, Pionek, Kostka
opisy OpisSeansu
katalogi KatalogSeansów
kontenery rzeczy fizycznych lub informacji Kino, SalaKinowa Plansza
rzeczy w kontenerach SalaKinowa, Miejsce Pole
inne współpracujące systemy SystemAutoryzującyPłatnościElektroniczne
potwierdzenia, rejestry, kontrakty, zagadnienia prawne Pokwitowanie, PotwierdzenieRezerwacji
instrumenty finansowe Czek, Gotówka
harmonogramy, instrukcje, dokumenty regularnie używane podczas wykonywania prac DziennaListaPromocji

Rozpoznane przez nas klasy pojęciowe są pokazane na poniższym diagramie.

Klasy pojęciowe dla gry Monopol

Pamiętaj, że wykonujesz analizę dziedziny, to nie jest projektowanie. Nie uwzględniaj artefaktów programowych, np. okienek, baz danych, itp. Wyobraź sobie, że programu nigdy nie napiszesz lub że zrobi to za ciebie ktoś inny. Oczywiście wyjątkiem są artefakty programowe należące do dziedziny którą modelujesz, na przykład możesz uwzględnić zewnętrzne systemy, z którymi twój system będzie współpracował, a jeżeli twoim celem jest stworzenie modelu dziedziny dla sieci komputerowej, to możesz uwzględnić pakiety, połączenia, itp.

Odnajdywanie powiązania

Powiązania (ang. association) między klasami wskazuje, że między ich egzemplarzami może występować jakaś zależność. W modelu dziedziny. W modelu dziedziny pokazujemy powiązania, które są niezbędne do wypełnienia wymagań informacyjnych i pomagają zrozumieć dziedzinę. Pokazanie zbyt wielu powiązań sprawi, że diagramy będą mało czytelne. Zazwyczaj warto pokazywać powiązania między klasami, jeżeli przez jakiś czas "trzeba pamiętać" o zależności między ich egzemplarzami. Dlatego mimo, że powiązania rysujemy między klasami to myślimy o ich egzemplarzach. Czy trzeba na przykład pamiętać na jakim Polu jest Pionek albo do jakiego Gracza należy. Oczywiście. Jednak informacji, że wartość wskazywana przez Kostkę wskazuje na które Pole się ruszyć nie trzeba przechowywać w modelu. Jest to metainformacja. Tak samo nie ma potrzeby zapamiętywać, że Gracz przesuwa Pionek.

Przy znajdywaniu powiązań również posłużymy się listą najczęściej spotykanych kategorii.

Lista często spotykanych kategorii powiązań
Kategoria Przykłady Klasy z dziedziny gry w Monopol
A jest transakcją związaną z inną transakcją B Płatność--RezerwacjaMiejsc
A jest pozycją transakcji B PozycjaRezerwacji--RezerwacjaMiejsc
A jest produktem lub usługą z transakcji lub pozycji transakcji B Bilet--SprzedażBiletu
A jest rolą związaną z transakcją B Klient--Płatność
A jest fizyczną lub logiczną częścią B Miejsce--SalaKinowa, SalaKinowa--Kino Pole--Plansza, Pole--KompletPól, GraWMonopol--Plansza, GraWMonopol--Kostka, GraWMonopol--Pionek
A fizycznie lub logicznie przechowywane w/na B Kasa--Kino Pionek--Pole, Pole--Plansza
A jest opisem B OpisSeansu--Seans
A jest rejestrowane/zgłaszane/utrwalane/pamiętane na/w B SprzedażBiletu--Kasa Pionek--Pole, GraWMonopol--Plansza
A jest uczestnikiem/pracownikiem/członkiem B Kasjer--Kino Gracz--GraWMonopol
A jest organizacyjną podjednostką B Kino--SiećKin
A używa lub zarządza lub posiada B Kasjer--Kasa Gracz--Pionek
A jest obok B PozycjaRezerwacji--PozycjaRezerwacji

Nazywanie powiązań nie zawsze jest proste. Wymyślając nazwę wiemy co mamy na myśli, ale nie każda nazwa, która pasuje pozwoli innym zorientować się o co nam chodziło. Dla wielu powiązań będzie na przykład pasować nazwa Dotyczy, ale nie przenosi ona wielu informacji. Pamiętaj o tym nazywając powiązania!

Odnajdując powiązania warto zastanowić się nad ich liczebnością (ang. multiplicity). Liczebność określa jak wiele egzemplarzy klasy A może być powiązane z jednym egzemplarzem klasy B. Na diagramach liczebność przedstawia się w postaci wyrażenia obok klasy A, tuż przy linii obrazującej powiązanie. Przykładowe wyrażenia liczebności to: 1 (dokładnie jeden), 11 (dokładnie jedenaście), 3, 5, 7 (trzy lub pięć lub siedem), 2..8 (od dwóch do ośmiu), 0..1 (zero lub jeden), 1..* (co najmniej jeden), * (dowolna ilość również zero). Określając liczebność pamiętaj, żeby wyrażać ograniczenia związane z dziedziną. Jeżeli na podstawie twojego modelu powstanie w przyszłości system obiektowy, te ograniczenia będą bardzo przydatne i na ich podstawie określone zostaną różne więzy spójności.

Klasy pojęciowe i powiązania dla gry Monopol

Dodawanie atrybutów

Wartości atrybutów (ang. attirbute) opisują egzemplarze klas pojęciowych. Dodawanie atrybutów jest w zasadzie prostsze niż odnajdywanie klas pojęciowych czy powiązań i zazwyczaj zostawia się je na koniec. Są jednak dwie pułapki.

Po pierwsze, trzeba pilnować, żeby wartości atrybutów rzeczywiście opisywały egzemplarze klas pojęciowych. Może się zdarzyć, że coś co wydaje nam się atrybutem klasy A powinno tak naprawdę być atrybutem klasy B, a między A i B powinno być powiązanie. Przykładowo numer jest atrybutem Miejsca, a nie Biletu.

Po drugie, niech atrybuty będą jedynie wartościami typów podstawowych --- "czystymi danymi" --- jak napisy, liczby, wartości logiczne czy daty. W przeciwnym przypadku prawdopodobnie znowu lepiej dodać klasę pojęciową i ustanowić z nią powiązanie. Przykładowo kierownik nie jest atrybutem Kina. To oddzielna klasa pojęciowa sama posiadająca wiele atrybutów, jak imię, nazwisko czy dataUrodzenia.

Uwaga: w pewnych sytuacjach coś co wydaje się być wartością typu podstawowego, wcale nią nie jest! Niektóre wartości liczbowe mają na przykład jednostki, które mogą być istotne, a część identyfikatorów mimo, że na pierwszy rzut oka jest liczbą lub napisem, ma pewną strukturę pozwalającą odczytać dodatkowe informacje.

Po uzupełnieniu o atrybuty nasz model dziedziny dla gry w Monopol wygląda następująco:

Częściowy model dziedziny dla gry Monopol

Nie jest to jeszcze wersja ostateczna. Nie uwzględniliśmy na przykład kart szansy/ryzyka, a być może w trakcie późniejszych prac (projektowania, kodowania lub dalszych iteracji) zdecydujemy się wprowadzić jakieś zmiany. Nie należy się tym jednak przejmować. Wystarczy, że przez godzinę lub dwie myśleliśmy o dziedzinie zadania. O to właśnie chodzi, żeby unikać "pędu do kodowania" i zastanowić się nad dziedziną. Pamiętaj również, żeby pracować iteracyjnie i nie zabierać się za wszystko na raz, tylko zacząć od tego co najbardziej ryzykowne.