Związki w UML czyli abstrakcja vs rzeczywistość

Wstęp

Tym razem o kil­ku powszech­nie popeł­nia­nych błę­dach w korzy­sta­niu z UML. Chodzi o poję­cia abs­trak­cji, meta­mo­de­li i zależ­no­ści oraz o związ­ki mię­dzy ele­men­ta­mi na dia­gra­mach. Kluczową, moim zda­niem, przy­czy­ną two­rze­nia złych” mode­li obiek­to­wych jest uży­wa­nie nota­cji UML do two­rze­nia mode­li struk­tu­ral­nych, nie mają­cych z obiek­to­wym para­dyg­ma­tem nic wspól­ne­go. Druga to nie­zro­zu­mie­nie poję­cia para­dyg­ma­tu obiek­to­we­go. Ogromna ilość dia­gra­mów wyko­na­nych z uży­ciem sym­bo­li nota­cji UML, z UML i para­dyg­ma­tem obiek­to­wym ma nie­wie­le wspólnego.

Najpierw kil­ka defi­ni­cji i pojęć.

Paradygmat pro­gra­mo­wa­nia (ang. pro­gram­ming para­digm) ? wzo­rzec pro­gra­mo­wa­nia kom­pu­te­rów przed­kła­da­ny w danym okre­sie roz­wo­ju infor­ma­ty­ki ponad inne lub cenio­ny w pew­nych oko­licz­no­ściach lub zasto­so­wa­niach. (Źródło: Paradygmat pro­gra­mo­wa­nia ? Wikipedia, wol­na ency­klo­pe­dia)

No to teraz obiek­to­wy paradygmat:

Programowanie obiek­to­we (ang. object-orien­ted pro­gram­ming) ? para­dyg­mat pro­gra­mo­wa­nia, w któ­rym pro­gra­my defi­niu­je się za pomo­cą obiek­tów ? ele­men­tów łączą­cych stan (czy­li dane, nazy­wa­ne naj­czę­ściej pola­mi) i zacho­wa­nie (czy­li pro­ce­du­ry, tu: meto­dy). Obiektowy pro­gram kom­pu­te­ro­wy wyra­żo­ny jest jako zbiór takich obiek­tów, komu­ni­ku­ją­cych się pomię­dzy sobą w celu wyko­ny­wa­nia zadań. Podejście to róż­ni się od tra­dy­cyj­ne­go pro­gra­mo­wa­nia pro­ce­du­ral­ne­go, gdzie dane i pro­ce­du­ry nie są ze sobą bez­po­śred­nio zwią­za­ne. (Źródło: Programowanie obiek­to­we ? Wikipedia, wol­na ency­klo­pe­dia)

albo:

Programowanie obiek­to­we lub ina­czej pro­gra­mo­wa­nie zorien­to­wa­ne obiek­to­wo (ang. object-orien­ted pro­gra­ming, OOP) to para­dyg­mat pro­gra­mo­wa­nia przy pomo­cy obiek­tów posia­da­ją­cych swo­je wła­ści­wo­ści jak pola (dane, infor­ma­cje o obiek­cie) oraz meto­dy (zacho­wa­nie, dzia­ła­nia jakie wyko­nu­je obiekt). Programowanie obiek­to­we pole­ga na defi­nio­wa­niu obiek­tów oraz wywo­ły­wa­niu ich metod, tak aby współ­dzia­ła­ły wza­jem­nie ze sobą. (Źródło: Programowanie obiek­to­we ? Encyklopedia Zarządzania

Słownik języ­ka pol­skie­go mówi:

współ­dzia­łać
1. ?dzia­łać wspól­nie z kimś?
2. ?przy­czy­niać się do cze­goś razem z inny­mi czyn­ni­ka­mi?
3. ?o mecha­ni­zmach, narzą­dach itp.: funk­cjo­no­wać w powią­za­niu z innymi?

wywo­łać ? wywo­ły­wać
1. ?woła­niem skło­nić kogoś do wyj­ścia skądś?
2. ?przy­po­mnieć sobie lub innym coś?
3. ?spo­wo­do­wać coś lub stać się przy­czy­ną cze­goś?
4. ?oznaj­mić coś publicz­nie?
5. ?oddzia­łać na kli­szę, bło­nę lub papier foto­gra­ficz­ny środ­ka­mi che­micz­ny­mi w celu uwi­docz­nie­nia obra­zu uta­jo­ne­go na mate­ria­le światłoczułym?

Tak więc stwier­dze­nie, że obiek­ty z sobą współ­dzia­ła­ją” ozna­cza, że wywo­łu­ją się” wza­jem­nie w celu spo­wo­do­wa­nia cze­goś kon­kret­ne­go. Innymi sło­wy obiek­ty two­rzą­ce pro­gram (sys­tem) są od sie­bie wza­jem­nie uza­leż­nio­ne. Dlatego pod­sta­wo­wym związ­kiem w pro­ce­sie ana­li­zy i pro­jek­to­wa­nia zorien­to­wa­ne­go obiek­to­wo jest wza­jem­na zależ­ność”, nazy­wa­na w ory­gi­nal­nej spe­cy­fi­ka­cji UML związ­kiem usłu­go­daw­ca-usłu­go­bior­ca”.

Zależności

Związek ten nale­ży utoż­sa­miać z każ­dą wza­jem­ną zależ­no­ścią. Z uwa­gi na to, że mamy wie­le typów zależ­no­ści, wska­zu­je­my kon­kret­ny typ z pomo­cą ste­reo­ty­pu («[nazwa_typu]»).

Najczęściej wystę­pu­ją­cy typ zależ­no­ści to zwią­zek uży­cia. Oznacza on, że jeden obiekt wywo­łu­je umie­jęt­no­ści (ope­ra­cje) inne­go czy­li uży­wa go” do reali­za­cja swo­je­go zada­nia. Związek taki ozna­cza­ny ste­reo­ty­pem «use»:

uml-diagram-klas-zwiazek-uzycia

F uży­wa (jest zależ­ny od) E (co do zasa­dy tu F nie jest samo­dziel­ny w tym co robi”).

Formą zależ­no­ści jest tak­że dość rzad­ko wyko­rzy­sty­wa­na abs­trak­cja («Abstraction»). Związek ten jest wyko­rzy­sty­wa­ny do łącze­nia dwóch pojęć, z któ­rych jed­no jest abs­trak­cją dru­gie­go. Inna czę­sto wyko­rzy­sty­wa­na zależ­ność to «instanceOf» ozna­cza zależ­ność mode­lu (obiek­tu) od jego meta­mo­de­lu (kla­sy­fi­ka­to­ra) a tak­że od meta­me­ta­mo­de­lu.

Tak więc model opro­gra­mo­wa­nia w nota­cji UML z uży­ciem obiek­to­we­go para­dyg­ma­tu powi­nien wyglą­dać mniej wię­cej tak:

Wzorzec BCE

Na dia­gra­mie uży­to sym­bo­li klas (gra­ficz­na repre­zen­ta­cja ste­reo­ty­pów) zaczerp­nię­tych wzor­ca archi­tek­to­nicz­ne­go BCE.

Realizacja i kompozycja

Dokumentowanie deta­li struk­tu­ry ele­men­tów np. repo­zy­to­rium, wyma­ga stwo­rze­nia kolej­ne­go dia­gra­mu: mode­lu struk­tu­ry obiek­tów repre­zen­tu­ją­cych np. zło­żo­ną struk­tu­rę obiek­tu nio­są­ce­go infor­ma­cje (np. z formularza).

uml-diagram-klas-zwiazki-realizacja

Korzystamy tu ze związ­ku reali­za­cja i związ­ku kom­po­zy­cja. Realizacja to zwią­zek pomię­dzy spe­cy­fi­ka­cją a jej reali­za­cją (pro­jek­tem, imple­men­ta­cją, itp.), wska­zu­je zależ­ność imple­men­ta­cji od jej mode­lu. C2 jest spe­cy­fi­ka­cją (opi­sem, doku­men­ta­cją) reali­za­cji D2. Najczęściej zwią­zek ten jest sto­so­wa­ny pomię­dzy spe­cy­fi­ka­cją inter­fej­su a jego imple­men­ta­cją a tak­że gene­ral­nie pomię­dzy abs­trak­cją a jej reali­za­cją. Typowym przy­kła­dem uży­cia tego związ­ku jest np. poka­za­nie na jed­nym dia­gra­mie abs­trak­cji bytu w repo­zy­to­rium i reali­za­cji jej struktury:

model-dziedziny-realizacja-repozytorium

Na dia­gra­mie uży­to tak­że związ­ku całość-część”: linia zakoń­czo­na wypeł­nio­nym rom­bem na jed­nym koń­cu. Romb wska­zu­je na całość”: ele­ment nad­rzęd­ny drze­wia­stej struk­tu­ry kon­struk­cji. Jest to spe­cjal­ny zwią­zek ozna­cza­ją­cy trwa­łe (kon­struk­cyj­ne) powią­za­nie pomię­dzy deta­la­mi skła­da­ją­cy­mi się na okre­ślo­ną całość. UWAGA! Nie ma on nic wspól­ne­go z poję­ciem rela­cji” zna­nym z teo­rii rela­cyj­nych baz danych!

Biorąc pod uwa­gę fakt, jakim jest her­me­ty­za­cja jako cecha obiek­to­wych kon­struk­cji, takie enti­ties” nie współ­dzie­lą mie­dzy sobą ŻADNYCH ele­men­tów (danych). Użycie na dnie” bazy danych, wspól­nej dla całej apli­ka­cji, bazy dopro­wa­dzo­nej do tak zwa­nej znor­ma­li­zo­wa­nej posta­ci, łamie wszel­kie zasa­dy obiek­to­wych kon­struk­cji: łamie pod­sta­wo­wą zasa­dę jaką jest her­me­ty­za­cja imple­men­ta­cji obiek­tów (zakaz jakie­go­kol­wiek współ­dzie­le­nia cze­go­kol­wiek, nie nale­ży mylić współ­dzie­le­nia z re-użyciem).

Generalizacja i asocjacja

Oprócz mode­li struk­tur, powsta­ją czę­sto mode­le poję­cio­we. Są to odręb­ne dia­gra­my. Ich celem jest doku­men­to­wa­nie związ­ków seman­tycz­nych i syn­tak­tycz­nych pomię­dzy klu­czo­wy­mi poję­cia­mi wyko­rzy­sty­wa­ny­mi w pro­jek­cie. Stanowią one nazwy obiek­tów i ich typy (atry­bu­ty klas to tak­że obiek­ty). Wykorzystywane są tu dwa rodza­je związ­ków: gene­ra­li­za­cja i aso­cja­cja. Są to związ­ki repre­zen­tu­ją­ce WYŁĄCZNIE logicz­ne powią­za­nia pomię­dzy poję­cia­mi, nie mode­lu­ją one struk­tur a ni implementacji!

Jeżeli jakieś poję­cie ma swo­je spe­cja­li­zo­wa­ne typy, lub z dru­giej stro­ny, gru­pa pojęć daje się uogól­nić innym nad­rzęd­nym poję­ciem (gene­ra­li­zo­wa­nie), sto­su­je­my zwią­zek gene­ra­li­za­cji. Związek ten (korzy­sta­nie z nie­go) ma sens tyl­ko gdy licz­ba typów to co naj­mniej dwa, co do zasa­dy zwią­zek gene­ra­li­za­cji słu­ży do gru­po­wa­nia. Jeżeli pomię­dzy poję­cia­mi ist­nie­je zwią­zek wyni­ka­ją­cy z dzie­dzi­ny pro­ble­mu (np. zwią­zek pomię­dzy zwie­rzę­ciem a kar­mą dla nie­go) mode­lu­je­my go linią cią­głą łączą­cą powią­za­ne tak poję­cia. Poniżej gra­ficz­ny przy­kład uży­cia tych związków:

zwiazki-generalizacji-i-asocjacje-w-modelu-pojeciowym

B1 i B2 to kon­kret­ne typy poję­cia A (typem jest tak­że poję­cie). Analogicznie B12 i B22 to typy poję­cia A3. Pomiędzy poję­cia­mi A i A3 ist­nie­je zwią­zek logicz­ny (moż­na go nazwać, wpi­su­jąc te nazwę na linii). Typy mogą mieć wię­cej niż jeden kon­tekst dla­te­go mogą zostać pogru­po­wa­ne a każ­da gru­pa otrzy­mu­je nazwę nazwa gru­py” (oryg. Generalization Sets). Nie ma sen­su zwią­zek gene­ra­li­za­cji pomię­dzy tyl­ko jed­ną parą pojęć, bo ozna­cza wte­dy po pro­stu toż­sa­mość. Np. poję­cie woje­wódz­two” w Polsce ma obec­nie szes­na­ście spe­cja­li­za­cji, mają one swo­je nazwy, i to jest jed­na gru­pa typów. Jednak woje­wódz­twa moż­na podzie­lić tak­że np. ze wzglę­du na wiel­kość na np. trzy gru­py: małe woje­wódz­two, śred­nie woje­wódz­two i duże woje­wódz­two, i to będzie dru­ga i nie­za­leż­na gru­pa typów.

Modele…

Wszystkie powyż­sze przy­kła­dy to dia­gra­my klas nota­cji UML, jed­nak jak widać każ­dy ma zupeł­nie inne prze­zna­cze­nie (jest mode­lem cze­go inne­go). Nie oma­wia­łem tu zupeł­nie dia­gra­mów klas mode­lu­ją­cych kod pro­gra­mów. Zaznaczę jedy­nie, że są to kolej­ne mode­le doku­men­to­wa­ne z uży­ciem dia­gra­mów klas nota­cji UML, i omó­wio­ne powy­żej związ­ki dzie­dzi­cze­nia i aso­cja­cje na mode­lach poję­cio­wych mają tam zupeł­nie inne znaczenie.

Modele mogą być róż­ne i doty­czyć róż­nych rze­czy (patrz Modele.…). Tu chcę zwró­cić uwa­gę na bar­dzo waż­ny aspekt: abs­trak­cyj­ne i rze­czy­wi­ste poję­cia w mode­lach (na dia­gra­mach). Dostrzegam ogrom­ny bała­gan nie tyl­ko w doku­men­tach pro­jek­to­wych ale tak­że i w lite­ra­tu­rze, gdzie auto­rzy poka­zu­ją wie­le róż­nych przy­kła­dów, któ­re nie­ste­ty są złe i pozba­wio­ne uzasadnienia.

Przede wszyst­kim mode­le dzie­li­my, jak już wspo­mnia­łem, na poję­cio­we i te mode­lu­ją­ce jakąś okre­ślo­ną rze­czy­wi­stość. Modele poję­cio­we to mode­le poka­zu­ją­ce poję­cia oraz seman­tycz­ne i syn­tak­tycz­ne związ­ki mie­dzy nimi. Modele poję­cio­we słu­żą do udo­ku­men­to­wa­nia dzie­dzi­no­wej tak­so­no­mii co z jed­nej stro­ny pozwa­la utrzy­mać peł­ną jed­no­znacz­ność doku­men­ta­cji a z dru­giej, na eta­pie imple­men­ta­cji, pozwa­la podej­mo­wać decy­zje o typach danych. Służą one np. do budo­wa­nia słow­ni­ków i ety­kie­to­wa­nia np. pól for­mu­la­rzy (pole Nazwa woje­wódz­twa, któ­re­go zawar­tość będzie wybie­ra­na ze słow­ni­ka zawie­ra­ją­ce­go szes­na­ście nazw). Na tych mode­lach poja­wia­ją się w zasa­dzie wyłącz­nie poję­cia sta­no­wią­ce abs­trak­cje i typy, nie są to mode­le żad­ne­go kodu, dzie­dzi­ny itp. Tu przy­po­mnę, że model dzie­dzi­ny sys­te­mu to model opi­su­ją­cy mecha­nizm jego (sys­te­mu, apli­ka­cji) dzia­ła­nia, repre­zen­to­wa­ny jest przez liter­kę M we wzor­cu MVC, poważ­nym błę­dem jest uzna­wa­nie tych mode­li za mode­le danych.

Modele struk­tu­ry to mode­le opi­su­ją­ce okre­ślo­ne kon­struk­cje”, głów­nie na dwóch pozio­mach abs­trak­cji: jako model i jako meta­mo­del. Z regu­ły, w pro­jek­tach zwią­za­nych z opro­gra­mo­wa­niem, ta kon­struk­cja to wła­śnie Model Dziedziny czy­li mecha­nizm dzia­ła­nia, tak zwa­na logi­ka biznesowa/dziedzinowa aplikacji.

Podsumowanie

Tak więc nie ma cze­goś takie­go jak dia­gram klas dla pro­jek­tu”. Mamy dla dane­go pro­jek­tu: model poję­cio­wy, mode­le logi­ki sys­te­mu, mode­le struk­tu­ry obiek­tów, mode­le imple­men­ta­cji. To wszyst­ko są dia­gra­my klas ale każ­dy z nich do model cze­goś inne­go”. Paradygmat obiek­to­wy jasno mówi: obiek­ty współ­pra­cu­ją, więc stan­dar­do­wym związ­kiem w mode­lach logi­ki dzia­ła­nia są związ­ki uży­cia a nie aso­cja­cje ani związ­ki dzie­dzi­cze­nia czy kom­po­zy­cji. Diagramy te nie są żad­ny­mi mode­la­mi danych mię­dzy inny­mi dla­te­go, że z zasa­dy para­dyg­mat obiek­to­wy ukry­wa je (her­me­ty­za­cja), na zewnątrz” dostęp­ne są wyłącz­nie publicz­ne ope­ra­cje obiek­tów. Utrwalanie obiek­tów (zapis war­to­ści atry­bu­tów np. w bazie danych) to zada­nie do roz­wią­za­nia dopie­ro na eta­pie imple­men­ta­cji, pole­ga­ją­ce na zagwa­ran­to­wa­niu zacho­wa­nia” sta­nów obiek­tów na czas wyłą­cze­nia zasi­la­nia, by nie ule­cia­ły” z pamię­ci kom­pu­te­ra, któ­ry jest śro­do­wi­skiem wyko­na­nia pro­gra­mu. Na eta­pie ana­li­zy obiek­to­wej i mode­lo­wa­nia logi­ki sys­te­mu nie mode­lu­je­my żad­nych danych.

Poniższy przy­kład, jakich wie­le w sie­ci, jest wzor­co­wym antyprzykładem.

(https://​www​.wie​dza​na​plus​.pl/​p​r​o​g​r​a​m​o​w​a​n​i​e​/​3​3​-​u​m​l​/​6​8​-​j​e​z​y​k​-​u​m​l​-​p​r​o​j​e​k​t​-​s​k​l​e​p​u​-​k​o​m​p​u​t​e​r​o​w​e​g​o​.​h​tml)

Pierwsza zła cecha tego dia­gra­mu to czę­sty błąd nazy­wa­ny popu­lar­nie prze­cią­ża­niem obiek­tów”: tu obiekt Faktura ma ope­ra­cje spo­rządź”. Klasyczny błąd archi­tek­to­nicz­ny pole­ga­ją­cy na obcią­ża­niu obiek­tu cudzą odpo­wie­dzial­no­ścią. Jeżeli kla­sa Faktura repre­zen­tu­je np. fak­tu­ry sprze­da­ży, to sys­tem mają­cy w pamię­ci kolek­cję setek fak­tur i każ­da z kodem (ma te ope­ra­cję) słu­żą­cym do jej spo­rzą­dze­nia był­by masa­krą zaję­to­ści pamię­ci. Dodam, że model taki nie ma nic wspól­ne­go z rze­czy­wi­sto­ścią, bo fak­tu­ry wysta­wia ktoś” a nie fak­tu­ra”. Trzecia rzecz: fak­tu­ra zaku­pu i fak­tu­ra sprze­da­ży to niczym nie róż­nią­ce się struk­tu­ry, więc two­rze­nie takie­go roz­róż­nie­nia jest pozba­wio­ne sen­su. To błę­dy poję­cio­we i ten dia­gram ma masę takich błę­dów. Druga wada: błęd­ne uży­cie związ­ku kom­po­zy­cji: powyż­szy dia­gram nale­ża­ło­by inter­pre­to­wać jako struk­tu­rę o jed­nej zwar­tej kon­struk­cji, np. takiej jak samo­chód skła­da­ją­cy się z setek pod­ze­spo­łów ale sta­no­wią­cy jed­nak jed­ną całość. Brak mode­lu poję­cio­we­go i słow­ni­ka powo­du­je wie­le nie­jed­no­znacz­no­ści. Np. zwią­zek pomię­dzy Klientem a rekla­ma­cją wska­zu­je, że Reklamacje są inte­gral­ną czę­ścią Klienta (tak jak koła i sil­nik są inte­gral­ną czę­ścią samo­cho­du) co nawet w świe­tle potocz­ne­go rozu­mie­nia tych słów kłó­ci się ze zdro­wym rozsądkiem.

Użycie związ­ków poję­cio­wych (aso­cja­cja) jest zupeł­nie nie­zro­zu­mia­łe w tym przy­pad­ku. Nazwa aso­cja­cji zawie­ra” nie ma kie­run­ku a więc nie wia­do­mo co jest zawar­te w czym. Związki zależ­no­ści tak­że są nie­ja­sne: jak inter­pre­to­wać np. zapis mówią­cy, ze obiek­ty kla­sy użyt­kow­ni­cy zale­żą od obiek­tów kla­sy Raporty? Jeżeli autor miał na myśli użyt­kow­nik uży­wa rapor­tów” to popły­nął w sfe­rę mowy potocz­nej”, to chy­ba naj­czę­ściej spo­ty­ka­ny błąd pole­ga­ją­cy na tym, że autor dia­gra­mu nadal pisze spe­cy­fi­ka­cję pro­zą, ale z uży­ciem sym­bo­li (tu UML) zamiast słów.

Mogę się jedy­nie domy­ślać, że autor dia­gra­mu miał w gło­wie” model rela­cyj­ny związ­ków encji i użył ikon z nota­cji UML w cał­ko­wi­cie innych zna­cze­niach niż ta nota­cja defi­niu­je. Takie dia­gra­my nie powin­ny powsta­wać, są one nie­ste­ty dowo­dem na to, że pro­gra­mi­ści mówią­cy te doku­men­ty z UML nic nie wyja­śnia­ją i są nie­pre­cy­zyj­ne, i tak musi­my sami powtó­rzyć te ana­li­zę” mają rację. Są tak­że dowo­dem, że są to jed­nak pro­jek­ty struk­tu­ral­ne a nie obiek­to­we, a uży­cie nota­cji UML pole­ga­ło na sko­rzy­sta­niu z zesta­wu ikon tak się to robi two­rząc nie­sfor­ma­li­zo­wa­ne sche­ma­ty blo­ko­we z uży­ciem np. pro­gra­mów do two­rze­nia pre­zen­ta­cji takich jak PowerPoint. Zapewne poza auto­rem tego dia­gram, nikt nie ma poję­cia o co w nim cho­dzi.… Jeżeli autor miał na celu udo­ku­men­to­wa­nie mode­lu danych” to powi­nien użyć nota­cji ERD. A tak to mamy sche­mat blo­ko­wy, w któ­rym ktoś użył UML jako biblio­te­ki sym­bo­li wpro­wa­dza­jąc czy­tel­ni­ka w błąd.

Z przy­kro­ścią muszę przy­znać, że od takich błę­dów nie są wol­ne tak­że nie­któ­re pod­ręcz­ni­ki i mate­ria­ły szko­le­nio­we… a tak­że doku­men­ty two­rzo­ne przez pra­cow­ni­ków wie­lu firm na ryn­ku IT.

P.S.

Na przy­kła­dy popraw­nych dia­gra­mów z uza­sad­nie­niem zapra­szam do mojej książ­ki i na moje szko­le­nia i warsz­ta­ty.

Specyfikacja UML v.2.5

Niestety spraw­ne” korzy­sta­nie z takich spe­cy­fi­ka­cji wyma­ga umie­jęt­no­ści czy­ta­nia mode­li poję­cio­wych (dia­gra­mów klas UML) opi­su­ja­cych syn­tak­ty­kę (syn­tax) jak wyżej (ich two­rze­nie też do łatwych nie nale­ży…). Przytaczam to jako źró­dło tego o czym tu pisałem.

W UML wszyst­ko jest kla­są”, związ­ki mię­dzy ele­men­ta­mi dia­gra­mów tak­że. Zostało to poka­za­ne w spe­cy­fi­ka­cji UML v.2.5.:

uml-zaleznosci
uml-klacyfikator
uml-zwiazki

W UML 2.5 prak­tycz­nie zni­ka w koń­cu dzie­dzi­cze­nie i agre­ga­cja. Uff… poni­żej pod­su­mo­wa­nie na jed­nym diagramie.

Dodatek [2022 – 07-22]

…chciał­bym zapy­tać o dzie­dzi­cze­nie w UML. Brałem ostat­nio udział w kil­ku roz­mo­wach o pra­cę. Moi roz­mów­cy czę­sto utrzy­mu­ją, że w UML jest to dzie­dzi­cze­nie. Mało tego, wyko­rzy­stu­ją to dzie­dzi­cze­nie na dia­gra­mach klas, w czymś co nazy­wa­ją mode­lem dzie­dzi­ny (oczy­wi­ście bez ope­ra­cji klas). Zajrzałem do spe­cy­fi­ka­cji UML i jestem tro­chę zdez­o­rien­to­wa­ny, ponie­waż poję­cie dzie­dzi­cze­nie dość czę­sto wystę­pu­je w tej doku­men­ta­cji, choć­by w tym fragmencie. 

W jakim zna­cze­niu jest tu uży­te poję­cie dzie­dzi­cze­nia? Czy jest gdzieś w spe­cy­fi­ka­cji wprost infor­ma­cja o usu­nię­ciu dzie­dzi­cze­nia z UMLa?

Porównując ze spe­cy­fi­ka­cją 2.4. nie ma, poję­cie dzie­dzi­cze­nia nadal jest obec­ne w języ­kach pro­gra­mo­wa­nia, a w spe­cy­fi­ka­cji 2.5.xx sło­wo inhe­ri­tan­ce” poja­wia sie tyl­ko 4 razy, i doty­czy wyłącz­nie komen­ta­rzy zwią­za­nych z uogólnieniami. 

Cytowany zwią­zek Generalizacji jest związ­kiem poję­cio­wym a nie struk­tu­ral­nym cze­goś ist­nie­ją­ce­go (struk­tu­ra mode­lo­wa­ne­go sys­te­mu). Formalnie w UML mamy zwią­zek Generalizacji, i jest to zwią­zek poję­cio­wy, ale nie ma w UML roz­dzia­łu Dziedziczenie”. Inherit w j. angiel­skim to tak­że prze­ję­cie cech po czymś” czy­li zwią­zek gene­ra­li­zo­wa­nia i spe­cja­li­zo­wa­nia. Generalziacja, jako zwią­zek ogól­ny-szcze­gól­ny, poka­zu­je że szcze­gól­ny przy­pa­dek, poję­cie i jego defi­ni­cja, ma wszyst­kie cechy przy­pad­ku ogól­niej­sze­go, więc pies jako szcze­gól­ny typ ssa­ka ma wszyst­kie cechy ssa­ka (cho­dzi o defi­ni­cje tego czym jest ssak). Czyli:
1. ssak: krę­go­wiec, któ­re­go mło­de kar­mią się mle­kiem mat­ki,
2. pies: <ssak> któ­ry szcze­ka,
więc:

pies: <krę­go­wiec, któ­re­go mło­de kar­mią się mle­kiem mat­ki>, któ­ry szczeka, 

czy­li pies (a kon­kret­nie defi­ni­cja psa) dzie­dzi­czy” po ssa­ku (defi­ni­cji ssa­ka) jego okre­ślo­ne cechy, czy­li ozna­cza to, że są one (cechy ssa­ka) np. dla psa i kota wspól­ne, a nie że, kot czy pies coś dzie­dzi­czy” po ssaku :). 

Dlatego w UML teraz jest napi­sa­ne, że mamy gene­ra­li­za­cję jako zwią­zek mię­dzy kla­sa­mi, ale nigdzie nie ma związ­ku dzie­dzi­cze­nia” mię­dzy klasami.

Tekst rozdz. 9.2.3.2. tłu­ma­czy­my tak, ze gene­ra­li­za­cja ozna­cza, że gene­ra­li­zo­wa­na defi­ni­cja (cechy czy­li atry­bu­ty i zacho­wa­nia) są wspól­ne (dzie­dzi­czą) dla spe­cja­li­zo­wa­nych ele­men­tów. W mode­lu poję­cio­wym (name­spa­ce) tak to dzia­ła. I teraz: model struk­tu­ry cze­go­kol­wiek ist­nie­ją­ce­go nie ma abs­trak­cji (a gene­ra­li­zo­wa­ne poję­cia to abs­trak­cje, poję­cie ssak to poję­cie abs­trak­cyj­ne). Opisując więc trak­tor jako pojazd czy doku­men­ty w księ­go­wo­ści jako doku­en­ty, nie ma nad nimi uogól­nień”, po któ­rych dzie­dzi­czą (sa to jed­nak poję­cia słow­ni­ko­we). Po tra­wie nie bie­ga­ją ssa­ki” tyl­ko psy, koty, lwy… 

Znakomita więk­szość zna­nych mi ludzi w IT nie odróż­nia mode­lu poję­cio­we­go od mode­lu struk­tu­ry sys­te­mu, któ­ry zbu­do­wa­ny jest (każ­dy) z real­nych ele­men­tów. W miej­sce sta­re­go” dzie­dzi­cze­nia w UML wpro­wa­dzo­no poję­cia: sza­blon (tem­pla­te) oraz rola (real­nym czymś w samo­cho­dzie jest sil­nik”, poję­cie napęd” to nazwa funkcji/roli okre­ślo­ne­go kom­po­nen­tu, ale nie pisze­my: „<sil­nik> dzie­dzi­czy po <napę­dzie>” tyl­ko „<sil­nik> peł­ni rolę <napę­du>” tak samo jak nie powie­my „<pies> dzie­dzi­czy po <zwie­rzę domo­we>” tyl­ko „<pies> peł­ni rolę <zwie­rzę­cia domowego>”. 

Języki pro­gra­mo­wa­nia pozwa­la­ją na tak zwa­ne re-uży­cie kodu, czy­li wycią­ga­nie pew­nych wspól­nych cech ponad kon­kret­ne komponenty/klasy (abs­trak­cja) po to by tyl­ko raz pisać kod kom­po­nen­tów mają­cych wspól­ne cechy. Jednak pro­jek­tu­jąc model dzie­dzi­ny” nie ma w niej abs­trak­cji, mając model dzie­dzi­ny (mecha­nizm dzia­ła­nia apli­ka­cji) zamie­nia­my gene­ra­li­za­cje i dzie­dzi­cze­nia” poję­cio­we na atry­bu­ty i typy real­nych rze­czy, tak to opi­sa­no książ­ce o mode­lo­wa­niu sys­te­mów już w 2007 roku: 

Oczywiście pro­gra­mi­sta może uży­wać gdzie chce dzie­dzi­cze­nia (ma taką moż­li­wość w każ­dym obiek­to­wym języ­ku pro­gra­mo­wa­nia) ale to jed­na z naj­gor­szych prak­tyk, bo łamią­cych klu­czo­wą zasa­dę jaką jest her­me­ty­za­cja kom­po­nen­tów („zakaz” współ­dzie­le­nia cze­go­kol­wiek). To dla­te­go od wie­lu lat OOP (Object-orien­ted Programming, języ­ki i pro­gra­mo­wa­nie obiek­to­we) i OOAD (Object-orien­ted Analysis and Design) to odręb­ne dzie­dzi­ny”.

UML version 2.5

Co praw­da for­mal­na publi­ka­cja wer­sji 2.5 UML to 1 marzec 2015 r. ale co ma wisieć nie uto­nie (spo­koj­ne prze­brnię­cie tych 794 stron wyma­ga cza­su i cier­pli­wo­ści), czy­li wzmian­ka i kil­ka słów z pierw­szych wra­żeń. Specyfikacja do pobra­nia tu:

Documents Associated With Unified Modeling Language (UML) Version 2.5 (Źródło: UML 2.5

Zdaję sobie spra­wę z tego, że poniż­sze nie wszyst­kim z Was wszyst­ko wyja­śni ale ten aku­rat wpis adre­su­ję dla tych z Was, któ­rzy korzy­sta­ją już z UML, nawet w bar­dzo pro­sty sposób.

Wersja 2.5 UML to wer­sja chy­ba prze­ło­mo­wa, bo:

  • zre­zy­gno­wa­no w koń­cu z podzia­łu na dwie czę­ści Infrastructure i Superstructure,
  • upo­rząd­ko­wa­no cały sys­tem poję­cio­wy nota­cji: jest to w koń­cu jed­na w peł­ni spój­na nota­cja (sys­tem kla­sy­fi­ka­to­rów, kie­dyś Infrastructure) oraz zestaw pre­de­fi­nio­wa­nych grup ste­reo­ty­pów z ich dedy­ko­wa­ną seman­ty­ką i syn­tak­ty­ką (kie­dyś Superstructure).
  • dia­gram jako poję­cie, obec­nie sta­no­wi jedy­nie kon­tekst a nie, jak kie­dyś zamknię­tą sub­no­ta­cję” (UML zaczy­nał w latach 90-tych jako zle­pek kil­ku nota­cji trzech autorów).

Obecnie mamy osiem typów dia­gra­mów (kopia z oryginału):

UML dia­grams may have the fol­lo­wing kinds of fra­me names as part of the heading:
? acti­vi­ty
? class
? com­po­nent
? deploy­ment
? inte­rac­tion
? pac­ka­ge
? sta­te machi­ne
? use case
In addi­tion to the long form names for dia­gram heading types, the fol­lo­wing abbre­via­ted forms can also be used:
? act (for acti­vi­ty fra­mes)
? cmp (for com­po­nent fra­mes)
? dep (for deploy­ment fra­mes)
? sd (for inte­rac­tion fra­mes)
? pkg (for pac­ka­ge fra­mes)
? stm (for sta­te machi­ne fra­mes)
? uc (for use case frames)

Jak widać, trzy­li­tro­wych skró­tów ozna­cza­ją­cych dia­gra­my jest o jeden mniej (sie­dem). To wyni­ka z tego, że wszyst­kie dia­gra­my w UML to tak na praw­dę dia­gra­my klas (ten typ dia­gra­mu nie ma swo­je­go dedy­ko­wa­ne­go skró­tu), z tym że sta­no­wią one kon­tek­sto­we pro­fi­le. Struktura poję­cio­wa tych dia­gra­mów (ich [[tak­so­no­mia]]):

UML The taxonomy of structure and behavior diagrams

W sto­sun­ku do UML 2.4 dia­gram pro­fi­lu jest teraz rów­no­praw­nym typem dia­gra­mu (czter­na­sty). Wszystkie poję­cia UML (con­structs) zosta­ły przy­dzie­lo­ne kon­tek­sto­wo to typów diagramów:

The con­structs con­ta­ined in each of the UML dia­grams are descri­bed in the clau­ses indi­ca­ted below.
? Activity Diagram – Activities
? Class Diagram – Structured Classifiers
? Communication Diagram – Interactions
? Component Diagram – Structured Classifiers
? Composite Structure Diagram – Structured Classifiers
? Deployment dia­gram – Deployments
? Interaction Overview Diagram – Interactions
? Object Diagram – Classification
? Package Diagram – Packages
? Profile Diagram – Packages
? State Machine Diagram – State Machines
? Sequence Diagram – Interactions
? Timing Diagram – Interactions
? Use Case Diagram – Use Cases

Należy to rozu­mieć w ten spo­sób: dia­gram aktyw­no­ści daje kon­tekst dla pojęć z gru­py acti­vi­ties” (aktyw­no­ści i czyn­no­ści oraz ich syn­tak­tycz­ne aso­cja­cje), dia­gram klas daje kon­tekst dla kla­sy­fi­ka­to­rów struk­tu­ral­nych”, itd.

Warto przy­pa­trzeć się swo­im narzę­dziom CASE, gdyż nie­ste­ty nie wszyst­kie mają wbu­do­wa­ny powyż­szy kla­so­wy” para­dyg­mat (w UML wszyst­ko jest kla­są). Wiele z nich nadal hoł­du­je zasa­dzie dia­gra­my jako odręb­ne nota­cje, obec­nie w UML w każ­dym typie dia­gra­mu moż­na użyć każ­de­go ele­men­tu nota­cji, dia­gram jako poję­cie to wyłącz­nie kon­te­ner nio­są­cy głów­ny kon­tekst dane­go mode­lu, bo przy­po­mi­nam, że dia­gram w UML to wyłącz­nie widok cało­ści lub czę­ści mode­lu z okre­ślo­nej per­spek­ty­wy i na okre­ślo­nym pozio­mie abstrakcji.

[uzu­peł­nie­nie 2015-11-21] Z pew­ną satys­fak­cją odkry­łem” (pier­wot­nie, pisząc ten arty­kuł mie­siąc temu, nie zwró­ci­łem na to uwa­gi), że zre­zy­gno­wa­no w koń­cu z poję­cia agre­ga­cji, zwa­nej w czę­ści lite­ra­tu­ry sła­bą kom­po­zy­cją”. Ta kurio­zal­na kon­struk­cja poję­cio­wa kłó­ci­ła się z poję­ciem i aso­cja­cji jako takiej i kom­po­zy­cji jako związ­ku całość część”. Nie ja jeden, jak śle­dzę dys­ku­sje człon­ków OMG na listach LinkedIn, dekla­ro­wa­łem, że nie rozu­miem” czym jest agre­ga­cja (chy­ba pierw­szym, któ­ry to gło­śno mówił był Martin Fowler). Na szczę­ście widać, że defi­ni­cja tego poję­cia nie wytrzy­ma­ła boju z logi­ką. Co praw­da sym­bol aso­cja­cji z pustym rom­bem” jest (tyl­ko) na liście sym­bo­li w dodat­ku B.6 (str. 718) jed­nak widać, że to relikt kom­pa­ty­bil­no­ści wstecz, w tre­ści całej spe­cy­fi­ka­cji to poję­cie nie jest w ogó­le uży­wa­ne. Generalnie mamy zwią­zek kom­po­zy­cji (peł­ny romb), a ele­ment skom­po­no­wa­ny może być rze­czy­wi­sty (part) lub abs­trak­cyj­ny (patrz rozdz. 11.2.3.2 Parts and Roles oraz 11.2.3.3 Connectors). Podobnie z dzie­dzi­cze­niem: nie ma dzie­dzi­cze­nia (korek­ta gru­dzień 2017, UML 2.5.1.).

Polecam całą spe­cy­fi­ka­cję, znacz­nie krót­sza od poprzedniej :).