Académique Documents
Professionnel Documents
Culture Documents
PRZYKADOWY ROZDZIA
SPIS TRECI
KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG
Wzorce projektowe.
Analiza kodu sposobem
na ich poznanie
Autor: Allen Holub
ISBN: 83-7361-948-8
Tytu oryginau: Holub on Patterns:
Learning Design Patterns by Looking at Code
Format: B5, stron: 464
TWJ KOSZYK
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK
CZYTELNIA
FRAGMENTY KSIEK ONLINE
Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
Spis treci
O Autorze ......................................................................................... 9
Przedmowa ..................................................................................... 11
Rozdzia 1. Wstp: programowanie obiektowe i wzorce projektowe .................... 15
Wzorce kontra cechy jzykw programowania .............................................................. 16
Czym waciwie jest wzorzec projektowy? .................................................................... 17
Czemu te wzorce maj w ogle suy? ......................................................................... 21
Rola wzorcw w procesie projektowania ....................................................................... 22
Napicia pomidzy wzorcami a prostot .................................................................. 23
Klasyfikacja wzorcw .................................................................................................... 25
O programowaniu, oglnie ....................................................................................... 26
Programowanie jzyka FORTRAN w Javie ............................................................. 28
Programowanie z otwartymi oczami ........................................................................ 31
Czym jest obiekt? ........................................................................................................... 32
Nonsens! .................................................................................................................. 32
Obiekt jest zbiorem zdolnoci .................................................................................. 33
Jak nie naley tego robi? ........................................................................................ 35
Jak zatem naley to robi prawidowo? ................................................................ 38
Automat komrkowy ...................................................................................................... 42
Metody zwracajce i ustawiajce s ze ............................................................................. 48
Sam wizualizuj swoje dane ...................................................................................... 52
JavaBeans i Struts .................................................................................................... 54
Dostrajanie ............................................................................................................... 55
ycie bez metod get i set .......................................................................................... 56
Kiedy stosowanie akcesorw i mutatorw jest uzasadnione? .................................. 59
Podsumowanie problematyki metod zwracajcych i ustawiajcych ........................ 62
Spis treci
7
Rozbudowa caego systemu o obsug jzyka SQL ..................................................... 300
Struktura moduu jzyka SQL ................................................................................ 301
Podzia danych wejciowych, ponowne omwienie wzorca wagi pirkowej
i analiza wzorca acucha odpowiedzialnoci ...................................................... 301
Skaner: wzorzec acucha odpowiedzialnoci ....................................................... 311
Klasa ParseFailure .................................................................................................. 319
Klasa Database ............................................................................................................. 321
Stosowanie klasy Database .................................................................................... 322
Wzorzec porednika ............................................................................................... 325
Zbir tokenw i pozostae stae .............................................................................. 330
Wzorzec interpretatora ................................................................................................. 337
Obsugiwana cz jzyka SQL ............................................................................. 337
Analiza funkcjonowania interpretera jzyka SQL .................................................. 359
Warstwa JDBC ............................................................................................................. 366
Wzorzec stanu i klasa JDBCConnection ...................................................................... 373
Wyraenia .............................................................................................................. 379
Wzorzec adaptera (zbiory wynikowe) .................................................................... 380
Wykaczanie kodu ................................................................................................. 385
Kiedy mosty nie zdaj egzaminu ............................................................................ 386
Uff! ............................................................................................................................... 387
Rozdzia 1.
Wstp: programowanie
obiektowe
i wzorce projektowe
W zwykych okolicznociach tego typu ksika powinna si rozpoczyna cytatem z Christophera Alexandra, architekta (budynkw, nie oprogramowania), ktry jako pierwszy
wprowadzi termin wzorca projektowego. Odkryem, e chocia Alexander jest wspaniaym czowiekiem i pisze naprawd wietne ksiki, jego dziea mog by zrozumiae
nie dla wszystkich, zatem pozwol sobie w tym miejscu pomin obowizkowy cytat.
Warto jednak pamita, e tezy prezentowane przez Alexandra stanowi podstawowe
rdo wspczesnych koncepcji wzorcw projektowych.
Podobnie, prawdziwym przeomem w kwestii zastosowa wzorcw projektowych
w wiecie oprogramowania bya ksika Design Patterns: Elements of Reusable Object-Oriented Software autorstwa Gammy, Helma, Johnsona i Vlissidesa (Addison-Wesley,
1995). (Czterej autorzy tej ksiki s przez wikszo projektantw dowcipnie nazywani
Band Czworga.) Moja ksika nie mogaby powsta, gdyby nie powstaa ksika Bandy
Czworga, zatem ja sam (podobnie jak chyba wszyscy programici stosujcy techniki
obiektowe) jestem winien autorom tej ksiki ogromne podzikowania. Tak czy inaczej, wspomniana przeze mnie ksika jest akademick prezentacj wzorcw, ktra dla
wikszoci pocztkujcych programistw z natury rzeczy bdzie po prostu niezrozumiaa. Postanowiem podj ryzyko zatracenia tej akademickiej precyzji i stworzy co
bardziej przystpnego.
16
17
18
raczej braku zrozumienia koncepcji wzorcw projektowych po stronie autorw tego rodzaju opinii: myl fragment kodu demonstrujcy jaki wzorzec z samym wzorcem. Majc
to na uwadze, sprbuj zaprezentowa rne przykady dla kadego z omawianych wzorcw, aby mg si przekona, jak odmienne mog by konkretne implementacje oparte
na tym samym wzorcu nie bd te wykorzystywa przykadw Bandy Czworga,
chyba e bd dotyczyy rzeczywistych problemw zwizanych z programowaniem (ten
warunek spenia tylko niewielka ich cz).
Analiz wzorcw projektowych dodatkowo komplikuje fakt, e rzeczywiste obiekty i klasy
nalece do poszczeglnych wzorcw niemal zawsze nale te do innych wzorcw.
Kiedy przyjrzysz si interesujcemu Ci rozwizaniu pod okrelonym ktem, dostrzeesz jeden wzorzec; jednak kiedy spojrzysz na to samo rozwizanie pod innym ktem,
zobaczysz zupenie inny wzorzec. Badania wzorcw bywaj jeszcze trudniejsze w sytuacjach, gdy wiele implementacji wzorcw opiera si na identycznych strukturach statycznych. Kiedy analizujesz przedstawione w ksice Bandy Czworga diagramy struktury
statycznej (zapisane w jzyku UML), wszystkie wygldaj bardzo podobnie wida
tam interfejs, klas klienta i klas implementacji. Rnic pomidzy wzorcami naley szuka w dynamicznym zachowaniu systemu i w celach realizowanych przez programist,
a nigdy w klasach czy w sposobie ich czenia.
Sprbuj zilustrowa wymienione problemy, posugujc si przykadem ze wiata
tradycyjnej architektury budynkw skupi si na dwch dziedzinach: wentylacji
i owietleniu.
Jeli chodzi o wentylacj, nie chc, by pokj robi wraenie dusznego. Jeli przeanalizujemy rozwizanie tego problemu w wielu naprawd komfortowych pomieszczeniach,
dostrzeemy w nich jeden wzorzec, ktry bd nazywa wentylacj przecinajc. Pomieszczenia nalece do tego wzorca maj rdo i ujcie powietrza ustawione naprzeciwko siebie na dwch przeciwlegych cianach, w dodatku na wysokoci okien. Powietrze dostaje si do pomieszczenia poprzez rdo, po czym przechodzi przez cae to
pomieszczenie i opuszcza je przez ujcie. Kiedy ju dysponowaem zidentyfikowanym
(i nazwanym) wzorcem, stworzyem krtki opis nazywany przez Band Czworga intencj ktry podsumowuje zarwno oglny problem, jak i rozwizanie wynikajce
z tego wzorca. W przypadku wentylacji przecinajcej moim celem byo wyeliminowanie poczucia dusznoci i zapewnienie wyszego komfortu przez umoliwienie bezporedniego przepywu powietrza w poziomie, na wysokoci okien. Mechanizmem architektonicznym, ktry ten cel realizuje jest logiczna reifikacja (wyjani to sowo za chwil)
wzorca. (Banda Czworga uywa w tym kontekcie sowa intencja, co jest dosy dziwne.
Sam nie bd si posugiwa tym sowem zbyt czsto, poniewa w moim odczuciu
znacznie lepszym sowem jest cel).
Reifikacja to brzydkie, ale do przydatne sowo w tym kontekcie. Sowo to nie jest
zbyt czsto stosowane w literaturze. Reifikacja znaczy dosownie materializacj, nadanie
czemu okrelonej treci i formy. Reifikacja koncepcji jest wic jej konkretn realizacj, a dla pojedynczej koncepcji mog istnie miliony moliwych reifikacji. Uywam
tego sowa (zamiast ktrego z bardziej popularnych wyrae), aby podkreli czym nie
jest wzorzec. Przykadowo, wzorzec nie jest egzemplarzem czy instancj. Kady
egzemplarz klasy jest identyczny (przynajmniej w sensie struktury) z wszystkimi
pozostaymi egzemplarzami tej samej klasy. Z pewnoci nie jest to cecha wzorca
19
20
Rysunek 1.1.
Poczona
reifikacja wentylacji
poprzecznej
i biura naronego
lini i rozszerzajcej klas majc udzia w danym wzorcu. Linie czce wzorce z klasami s oznaczane nazwami rl odgrywanych przez te klasy w odpowiednich wzorcach.
Okno od strony poudniowo-zachodniej peni funkcj wlotu powietrza dla wentylacji poprzecznej, natomiast drzwi naprzeciwko tego okna s ujciem powietrza. Dwa pozostae
okna nie odgrywaj adnej roli we wzorcu wentylacji poprzecznej, poniewa s rozmieszczone na cianach przylegajcych do ciany poudniowo-zachodniej. Skupmy si teraz na
czym innym okna poudniowo-zachodnie i poudniowo-wschodnie nale do wzorca
biura naronego, poniewa peni funkcj dwch rde naturalnego wiata. Ani drzwi,
ani okno pnocno-zachodnie nie nale do tego wzorca projektowego, poniewa nie
stanowi wystarczajcych rde wiata. Okno od strony poudniowo-zachodniej jest
o tyle interesujce, e naley do dwch wzorcw projektowych jednoczenie peni
funkcj rda powietrza we wzorcu wentylacji poprzecznej oraz rda wiata
we wzorcu biura naronego. Obiekty i klasy wystpujce w rozmaitych wzorcach czsto
wzajemnie si mieszaj w podobny sposb.
Kluczowe znaczenie ma zrozumienie, e identyfikacja wzorcw nie jest moliwa wycznie na podstawie analizowanej struktury. Przykadowo, wentylacja moe by blokowana np. przez meble wwczas adne z okien nie bdzie stanowio rda powietrza.
Podobnie, jedno z okien moe si znajdowa metr od ciany ssiedniego budynku lub
czy gabinet z korytarzem wwczas nie jest wystarczajcym rdem naturalnego
wiata (cho niewykluczone, e sprawdza si w roli rda lub ujcia powietrza). Kiedy
bdziesz analizowa rzeczywiste wzorce, przekonasz si, e do identyfikacji wzorca projektowego w programie komputerowym niezbdna jest wiedza zwizana z kontekstem
(wcznie ze znajomoci zamierze architekta). Nie mona identyfikowa wzorcw
projektowych wycznie na podstawie diagramw UML. Musisz zna docelowe (a wic
zgodne z zamierzeniami architekta) zastosowanie poszczeglnych obiektw lub klas.
W kolejnych rozdziaach bdziesz mia okazj zapozna si z wieloma przykadami
tego niezwykego zjawiska.
21
22
pytanie: Co tak naprawd prbuj osign i czy istniej jakie wzorce, ktre mogyby
mi to zadanie uatwi? (do znajdowania waciwych wzorcw wykorzystywaem te
fragmenty dostpnych opisw, ktre byy powicone ich przeznaczeniu). Kiedy odpowied brzmiaa tak, bez zastanowienia uywaem wybranego wzorca. Szybko odkryem, e takie podejcie z jednej strony znacznie skraca czas projektowania, z drugiej
strony przyczynia si do poprawy jakoci projektu. Im lepiej znaem potrzebne wzorce,
tym szybciej mogem pracowa nad kolejnymi projektami. Co wicej, moje pocztkowe
wersje projektw wymagay znacznie mniejszej liczby poprawek ni projekty przygotowywane w sposb tradycyjny.
Zapaem bakcyla.
Wzorce stanowi organizacyjny szkielet, ktry zasadniczo poprawia moliwoci komunikacyjne, bdce przecie w duszej perspektywie prawdziwym celem projektu. Dyskusje, ktre poprzednio wymagay godzin, teraz wanie dziki wzorcom zajmuj
tylko kilka minut, co powoduje, e wszystkie osoby zaangaowane w prace nad projektem mog realizowa swoje zadania szybciej. Swego czasu uwanie czytaem wszystkie
materiay, do ktrych mogem dotrze, i odkryem, e ksika Bandy Czworga dotyczya jedynie warstwy wierzchniej tego gbokiego tematu. W internecie i w literaturze
branowej ukazyway si setki udokumentowanych wzorcw projektowych, z ktrych
wiele miao zastosowanie w wykonywanej przeze mnie pracy. Z czasem doszedem do
przekonania, e wanie solidna wiedza o wzorcach przydatnych w mojej pracy moe
by zasadniczym elementem decydujcym o szybkoci i jakoci wykonywania zada.
(Przez solidn wiedz o wzorcach rozumiem ich znajomo na pami, a wic tak,
ktra nie bdzie wymagaa wertowania ksiek).
Rola wzorcw
w procesie projektowania
Kiedy wzorce zaczy by wykorzystywane w procesach projektowania i jaka jest ich
rola w tych procesach? Odpowied na to pytanie rni si w zalenoci od uytej metodyki (mam nadziej, e uywasz jakiej metodyki), jednak zainteresowanie wzorcami
projektowymi wynika przede wszystkim z codziennych problemw rozwizywanych
na poziomie implementacji, zatem rde popularnoci wzorcw w procesach projektowych naley upatrywa w zblieniu warstw projektowania i implementacji. Waniejsze
jest inne pytanie: Kiedy koczy si analiza (ktra jako taka wie si z dziedzin problemu) i rozpoczyna projektowanie (ktre z natury rzeczy dotyczy implementacji)?
Najlepsz znan mi analogi jest projektowanie i konstruowanie budynkw. Plany
budynkw nie obejmuj wszystkich szczegw konstrukcyjnych. Najczciej pokazuj rozmieszczenie murw, ale nie mwi o sposobie ich wznoszenia. Okrelaj miejsca instalacji wodno-kanalizacyjnej, ale nie definiuj rozmieszczenia wszystkich rur.
Dopiero w czasie konstruowania budynku projektowane s konkretne rozwizania
w zakresie wznoszenia murw i prowadzenia sieci wodno-kanalizacyjnej, jednak proponowane tam rozwizania rzadko s w peni realizowane, poniewa proces implementacji
23
stawia przed budowniczymi konkretne problemy do rozwizania (czsto nieprzewidywalne w fazie przygotowywania projektu). Przykadowo, ciela moe zastosowa okrelony wzorzec rozmieszczenia rub i gwodzi, ktry zagwarantuje odpowiednio mocn
konstrukcj ciany. Projekt przewanie mwi tylko o miejscu, w ktrym powinna stan ciana, nie wspomina jednak o sposobie jej konstruowania.
Z analogiczn sytuacj mamy do czynienia w wiecie oprogramowania: w przypadku
wikszoci przedsiwzi programistycznych proces projektowania powinien si zakoczy w punkcie, w ktrym dobry programista moe bez trudu ten projekt zaimplementowa. Nie jestem w stanie wyobrazi sobie opisu techniki tworzenia okien w podsystemie graficznego interfejsu uytkownika Swing zawartego w projekcie. Jest to jedno
z tych zada, ktre programista po prostu powinien potrafi zrealizowa; a jeli kod
jest pisany z zachowaniem profesjonalnych standardw (a wic z uwanie dobranymi
nazwami, waciwym formatowaniem, komentarzami w miejscach, gdzie jest to konieczne
itp.), decyzje podejmowane w fazie implementacji i tak powinny zosta odpowiednio
udokumentowane.
W efekcie wzorce projektowe rzadko s szczegowo opisywane w dokumentach tworzonych na etapie projektowania zamiast tego reprezentuj decyzje podejmowane
przez osoby odpowiedzialne za implementacj. Wzorce stosowane przez te osoby niemal nigdy nie s dogbnie dokumentowane, zwykle same nazwy elementw tych wzorcw (lub inne komentarze) powinny w stopniu wystarczajcym identyfikowa podejmowane dziaania. (Przykadowo, klasa WidgetFactory jest reifikacj wzorca klasywytwrni).
Istniej oczywicie wyjtki od reguy oddzielania wzorcw od waciwych projektw.
W wiecie oprogramowania odpowiednik okien wystpujcych we wzorcu naronego
biura moe si pojawia w dokumentach projektowych (ktre wskazuj programistom
miejsca rozmieszczenia okien). Podobnie, bardzo skomplikowane systemy, ktrych projekty wymagaj stosowania znacznie bardziej szczegowych opisw (tak jak plany architektoniczne dla drapacza chmur s duo bardziej szczegowe od planw dla domku
jednorodzinnego), czsto ju w wyniku fazy projektowania maj dogbnie udokumentowane wzorce projektowe.
24
25
Z drugiej strony, budowa w kodzie rdowym blokw wzorcw (np. przez czste wykorzystywanie interfejsw) zawsze jest rozwizaniem korzystnym, nawet wtedy, gdy stosowanie w peni rozwinitych wzorcw nie jest uzasadnione. Interfejsy nadmiernie nie
komplikuj kodu rdowego, a ewentualny rozwj tego kodu w przyszoci bdzie
znacznie prostszy, jeli system od pocztku bdzie budowany na podstawie jasnej struktury interfejsw. Koszt takiego dziaania jest stosunkowo niski, natomiast potencjalne
korzyci s bardzo due.
Klasyfikacja wzorcw
W niektrych sytuacjach przydaje si klasyfikacja wzorcw, ktra uatwia wybr waciwych rozwiza. W tabeli 1.1 (pochodzcej z ksiki Bandy Czworga) przedstawiono
jeden ze sposobw podziau wzorcw projektowych. Moesz jednak samodzielnie tworzy podobne tabele, w ktrych bdziesz dzieli wzorce na kategorie wedug dobranych przez siebie kryteriw.
Tabela 1.1. Klasyfikacja wzorcw projektowych wedug Bandy Czworga
Cel
Klasa
Z
a
k
r
e
s
Konstrukcyjne
Strukturalne
Czynnociowe
Metoda wytwrcza
Adapter klas
Interpretator
Metoda szablonowa
Wytwrnia abstrakcji
Adapter obiektu
acuch odpowiedzialnoci
Budowniczy
Most
Polecenie
Prototyp
Kompozyt
Iterator
Singleton
Dekorator
Mediator
Fasada
Memento
Waga pirkowa
Obserwator
Porednik
Stan
Strategia
Wizytator
Banda Czworga podzielia wzorce projektowe na dwa zakresy: wzorce klas wymagaj
reifikacji implementacji mechanizmu dziedziczenia (sowo kluczowe extends), natomiast wzorce obiektw powinny by implementowane wycznie z wykorzystaniem
mechanizmu dziedziczenia interfejsw (sowo kluczowe implements). To nie przypadek, e istnieje znacznie wicej wzorcw klas ni wzorcw obiektw. (Wicej informacji na ten temat znajdziesz w nastpnym rozdziale).
W ramach tych dwch zakresw wzorce s dalej dzielone na trzy kategorie. Wzorce
konstrukcyjne dotycz wycznie tworzenia obiektw. Przykadowo, wzorzec wytwrni
abstrakcji zapewnia mechanizmy tworzenia obiektw bez znajomoci klas, do ktrych te
nowe obiekty nale. (Na tym etapie troch upraszczam rzeczywiste znaczenie tego wzorca, ale zagadnienia te szczegowo wyjani w dalszej czci tej ksiki). Wszystkie
26
O programowaniu, oglnie
Kolejnym wanym zagadnieniem, ktre musz przynajmniej oglnie omwi jeszcze
przed przystpieniem do analizy samych wzorcw jest projektowanie obiektowe (zorientowane obiektowo).
Po pierwsze, projektowanie obiektowe (ang. Object-Oriented Design OOD) oraz programowanie obiektowe (ang. Object-Oriented Programming OOP) to dwie zupenie
rne dziedziny. Proces projektowania rozpoczyna si od gromadzenia wymaga i wie
si z systematycznym realizowaniem takich zada jak analiza przypadkw uycia
efektem tego procesu jest projekt, na podstawie ktrego programista moe opracowywa
27
28
si do znacznego poprawienia jakoci programu, a w skrajnych przypadkach moe t jako dodatkowo obniy. Niepotrzebne komplikacje a wiele wzorcw projektowych
jest skomplikowanych niczego nie poprawi.
Prosz wic, aby nie myli zagadnie omawianych w tej ksice z procesem projektowania obiektowego jako caoci. Wzorce s tylko niewielk czci tej ukadanki
w niektrych przypadkach ich udzia jest wrcz minimalny. Nie jest to ksika o projektowaniu obiektowym, tylko o przeksztacaniu projektw obiektowych w konkretne
implementacje. Aby jednak skutecznie stosowa wzorce projektowe, musisz wiedzie,
jak projektowa. Musisz zna proces projektowania. Na wspomnianej w przedmowie
stronie internetowej wymieniem wiele ksiek powiconych projektowaniu i zalecam
ich uwane przeczytanie.
29
nie przekazuj danych do innych obiektw, chyba e jest to absolutnie konieczne (nawet
wwczas przekazywane dane s hermetycznie zamykane w ramach tworzonych w tym
celu obiektw). Te dwie koncepcje (ukrywanie implementacji i abstrakcja danych) w wiecie systemw obiektowych maj kluczowe znaczenie.
Dobrym sposobem odrniania systemw obiektowych od systemw proceduralnych
jest analiza efektw wprowadzanych zmian. W systemach proceduralnych wszelkie zmiany wpywaj na pozostae skadniki programu, a due zmiany w dziaaniu programu wymagaj zwykle bardzo gbokich i rozlegych zmian w caym kodzie. W systemach obiektowych niezbdne modyfikacje mona wprowadza tylko w wybranych punktach.
Pojedyncza zmiana w kodzie systemu obiektowego moe powodowa znaczne zmiany
w zachowaniu caego programu. Przykadowo, jeli decydujesz si na zmian formatu
danych wykorzystywanego do przechowywania informacji, w przypadku systemu proceduralnego musiaby zmieni kod w wielu miejscach, poniewa dane s przetwarzane
przez wiele procedur; w systemie obiektowym zmiany bd dotyczyy wycznie obiektu
odpowiedzialnego za skadowanie danych.
Oczywicie takie reguy programowania obiektowego jak zapewnianie abstrakcji danych
(ukrywanie sposobu dziaania zestawu funkcji przez chowanie struktur danych przed
uytkownikami tych funkcji) istniay od dawna i stanowiy podstaw technik tworzenia
wysokiej jakoci oprogramowania w rozmaitych rodowiskach i jzykach take
proceduralnych. Przykadowo, zarwno system obsugi operacji wejcia-wyjcia na
plikach w jzyku C, jak i biblioteka Curses Kena Arnolda s rozwizaniami obiektowymi.
System proceduralny moe miejscami wyglda jak system obiektowy. System czysto
obiektowy charakteryzuje si przede wszystkim konsekwentnym i skrupulatnym stosowaniem pewnych regu (np. wspominanej ju abstrakcji danych).
Systemy obiektowe odrnia od systemw proceduralnych jeszcze jeden kluczowy
element. Przykadowo, systemy obiektowe w wikszoci przypadkw odwzorowuj (modeluj) procesy wiata rzeczywistego. Ten tok mylenia moe Ci doprowadzi do oglnej koncepcji procesu projektowania obiektowego; poniewa jednak ta ksika w gwnej mierze dotyczy struktury obiektowej, nie bd powica tym zagadnieniom zbyt
wiele czasu.
Wiele osb, ktre wychoway si w wiecie systemw proceduralnych sdzi, e obiektowe podejcie do problemw informatycznych jest czym niewaciwym. Zawsze jestem
zdumiony, kiedy czytam o kontrowersjach wywoanych przez moje artykuy o technikach
programowania obiektowego. Kiedy opublikowaem (w internetowym magazynie JavaWorld) wstpny zarys tej ksiki, doznaem prawdziwego szoku, czytajc obelywe
opinie o rzekomym oderwaniu prezentowanych koncepcji od rzeczywistoci koncepcji, ktre przewijaj si w literaturze informatycznej od trzydziestu lat. Byem nazywany dyletantem, szukajcym po omacku, niegodziwcem, gupkiem i opisywany
kilkoma innymi epitetami, ktrych nie powinienem tutaj przytacza. Moje artykuy byy
przez niektrych okrelane jako durne i pozbawione najmniejszego sensu. Jeden
z czytelnikw posun si nawet do fizycznych grb, rozpoczynajc swj napastliwy list
(szybko usunity przez administratora witryny) w nastpujcy sposb: TEEMU [sic]
AUTOROWI KTO WRESZCIE POWINIEN ROZWALI EB PRTEM!
30
Nie naley utosamia tego, co jest nam znane, z tym, co jest prawidowe. Wielu programistw zakada, e biblioteki, ktre regularnie wykorzystuj w swojej pracy s waciwe; a jeli ktra z nich wykonuje pewne operacje w okrelony sposb, programici
ci uwaaj, e wanie ta technika realizacji tego typu operacji jest standardem. Takie
postrzeganie swojego rodowiska mona obserwowa szczeglnie czsto u osb, ktre
uczyy si programowania z podrcznikw opisujcych rozwizywanie konkretnych
problemw i realizacj cile wybranych zada. Jeli jedyn architektur, z ktr kiedykolwiek mieli do czynienia, byo EJB lub Struts, bd klasyfikowali jako niewaciwe
wszelkie rozwizania nieprzypominajce ani EJB, ani Struts. To, e w przeszoci realizowalimy zadania w okrelony sposb, wcale nie oznacza, e by to sposb najlepszy;
gdyby rzeczywicie tak byo, nadal programowalibymy w jzykach asemblerowych.
Wiele lat temu odbyem bardzo interesujc rozmow z osob, ktra pracowaa w firmie
Microsoft nad rodowiskiem programowania w jzyku C++ i nad bibliotek Foundation Class (MFC). Kiedy stwierdziem, e MFC nie jest bibliotek obiektow, odpowiedzia, e doskonale zdaje sobie z tego spraw, ale wikszo ludzi programujcych dla
systemw firmy Microsoft po prostu nie rozumie regu rzdzcych wiatem obiektw.
Powiedzia te, e uczenie ludzi programowania obiektowego nie jest zadaniem Microsoftu. Efekt by taki, e Microsoft celowo stworzy system proceduralny w jzyku C++,
poniewa wanie taki system by atwiejszy do zrozumienia. Teoria o trudnym do
zrozumienia programowaniu obiektowym jest w firmie Microsoft zakorzeniona tak gboko, e nawet struktura interfejsw API technologii .NET jest w istocie proceduralna,
a np. jzyk programowania C# zawiera mechanizmy wrcz zachcajce do mylenia proceduralnego. Nic dziwnego, e wiele aplikacji firmy Microsoft jest tworzonych wbrew
podstawowym reguom rzdzcym systemami obiektowymi. Wielu spord programistw tej firmy podchodzi bardzo nerwowo do wszelkich technik obiektowych, ktre
nie s zgodne z rozwizaniami zastosowanymi w ramach technologii .NET. Myl to,
co jest im znane, z tym, co prawidowe.
Nie prbuj do systemw obiektowych przykada miary typowej dla systemw proceduralnych, nie krytykuj te opisywanych przeze mnie technik obiektowych tylko dlatego, e nie s zgodne z koncepcj programowania proceduralnego. Wiele popularnych
poj zwizanych z programowaniem obiektowym mogo w ogle nie wystpowa
w istniejcym kodzie, ktry miae okazj analizowa. Twierdzenie, e ktra z technik
kodowania jest niewykonalna w systemach obiektowych wcale nie musi oznacza, e
dana technika w ogle nie ma zastosowa. Bd o tym przypomina za kadym razem,
gdy bd analizowa obiektowe podejcie do jakiego problemu.
I wreszcie pamitaj, e rozwizanie czysto obiektowe nie zawsze jest konieczne ani
najwaciwsze. Tak jak w przypadku wikszoci decyzji podejmowanych w fazie projektowania rozwiza, koncepcja projektowania obiektowego ma pewne wady i moe
by rdem dodatkowego ryzyka. Przykadowo, prosta witryna internetowa zbudowana
na podstawie serwletw, ktra stanowi tzw. cienki fronton bazy danych, prawdopodobnie nie musi by tworzona zgodnie z surowymi reguami programowania obiektowego.
W tym przypadku ryzyko sprowadza si do nadmiernego komplikowania kodu (nawet
uniemoliwiajcego waciwe zarzdzanie) w zwizku z naturaln ewolucj programu.
Podobnie, wielu programistw nie rozumie koncepcji programowania obiektowego,
jeli wic Twj system nie ma okrelonych dugoterminowych wymaga w zakresie konserwacji, i jeli mona przyj, e wymagania biznesowe nie ulegn zmianie, przypisanie
31
32
Nonsens!
Bjarne Stroustrup, twrca jzyka programowania C++, scharakteryzowa kiedy programowanie obiektowe jako programowanie zorientowane na bekot techniczny i z pewnoci jednym z najczciej naduywanych (lub przynajmniej uywanych w sposb zupenie bezmylny) sw-bekotw jest sam obiekt. Poniewa wanie koncepcja obiektu
ma charakter centralny, precyzyjne wyjanienie, czym faktycznie jest obiekt, ma zasadnicze znaczenie dla rozumienia systemw obiektowych i ich potrzeb.
Po pierwsze, system obiektowy powiniene traktowa jak stado inteligentnych zwierzt
(zbir obiektw) zamknitych w Twoim komputerze, ktre rozmawiaj, przesyajc
pomidzy sob komunikaty. Wyobra sobie te obiekty. Klasy s tutaj nieistotne
maj jedynie charakter struktur pomocniczych stworzonych z myl o atwiejszej pracy
kompilatora. Zwierzta tworzce taki system mog by klasyfikowane (grupowane),
jeli maj podobne waciwoci (jeli np. potrafi obsugiwa te same komunikaty, co
inne obiekty nalece do tej samej klasy). Programici mwicy o klasach tak naprawd
maj na myli klasy obiektw. Oznacza to, e obiekty majce te same waciwoci tworz jedn klas obiektw. S to rozwaania na poziomie jzykowym (nie jest to wic
33
techniczny bekot) i wanie ten sposb jest najwaciwsz form mwienia o systemach
obiektowych. Zawsze mwimy o projektowaniu obiektowym, nigdy o projektowaniu
klasowym.
Najwaniejszym aspektem caej koncepcji projektowania obiektowego jest abstrakcja
danych. Wanie w abstrakcji danych tkwi tajemnica projektowania tego typu programw. Wszystkie informacje s ukrywane. Poszczeglne obiekty nie maj pojcia
o zawartoci pozostaych obiektw nie wiedz o nim wicej ni Ty o woreczku
ciowym swojego wspmaonka. (Zarwno w przypadku obiektw, jak i wspomnianego woreczka ciowego zapewne adna ze stron nawet nie chce tej brakujcej
wiedzy zdoby).
By moe miae kiedy okazj czyta ksik, ktrej autor dowodzi, e obiekt jest
struktur danych poczon ze zbiorem funkcji, nazywanych metodami, przetwarzajcych
t struktur danych. Nonsens! Bzdura!
swoich kontraktw.
Wszystkie dane s prywatne. Kropka. (Ta regua powinna by stosowana
34
35
oznaczaoby wczenie tych szczegw do kontraktu obiektu, a wic wykluczenie moliwoci modyfikowania implementacji (np. w odpowiedzi na wykrycie bdu lub pojawienie si nowych wymaga biznesowych).
Podobnie, regu zapewniania prywatnoci wszystkich danych obiektu naley interpretowa w nastpujcy sposb jeli ktry ze skadnikw obiektu nie jest prywatny,
automatycznie staje si czci kontraktu, zatem nie moe by modyfikowany. W pewnych (rzadkich) sytuacjach decyzja o publicznym deklarowaniu pola obiektu moe by
poprawna, ale jej nastpstwa zawsze s bardzo powane.
Pojcie kontraktu odgrywa te istotn rol w trzeciej z wymienionych regu. Idealnym
rozwizaniem jest ograniczenie zakresu zmian do pojedynczej klasy, jednak w wikszoci
przypadkw uniknicie wzajemnych zalenoci jest po prostu niemoliwe. Przykadowo, klasa HashMap wymaga od przechowywanych obiektw implementowania metody
hashCode(). To i podobne wymagania musz by czci kontraktw przechowywanych
obiektw.
36
Rozwizanie obiektowe jest prb hermetycznego zamknicia tych skadnikw oprogramowania, ktre najprawdopodobniej bd podlegay zmianom w ten sposb modyfikowana cz programu nie bdzie miaa wpywu na jego pozostae skadniki. Przykadowo, typowym rozwizaniem obiektowym dla opisanego przed chwil problemu
jest zastosowanie klasy Name, ktrej obiekty bd wiedziay nie tylko jak wywietla
swoje informacje, ale take jak si inicjalizowa. Wywietlanie nazwiska bdzie wwczas wymagao uycia polecenia Wywietl swoje informacje w tym miejscu i przekazania obiektu klasy Graphics (a by moe take obiektu klasy Container, za porednictwem ktrego obiekt nazwiska bdzie mg umieci przechowywane dane w panelu
JPanel). Obiekt klasy Name moe oczywicie wybra rozwizanie polegajce na utworzeniu kontrolki TextField, ale decyzja w tym wzgldzie naley wycznie do niego.
Ciebie, programist, po prostu nie interesuje sposb, w jaki obiekt nazwiska bdzie si
inicjalizowa (przynajmniej do czasu, kiedy ta inicjalizacja przebiega prawidowo). Implementacja tego obiektu moe nie tworzy adnych elementw interfejsu uytkownika moe np. pobiera warto pocztkow przez wykonanie odpowiedniego dania
na bazie danych lub za porednictwem sieci komputerowej.
Wracajc do mojej krytyki jzyka Visual Basic sprzed kilku akapitw, przyjrzyjmy si
typowemu, strukturalnemu sposobowi generowania elementw interfejsu uytkownika
przez ten jzyk (lub niezliczone systemy podobne do Visual Basica): tworzysz klas
Frame, ktrej zadaniem jest gromadzenie komunikatw przychodzcych z kontrolek
(z obiektw kontrolek) w odpowiedzi na dziaania podejmowane przez uytkownika.
Klasa Frame przekazuje te komunikaty dalej do systemu obiektw. Zbudowany w ten
sposb kod zazwyczaj przyjmuje nastpujc posta:
1. Wyciganie jakiej wartoci za pomoc metody get.
2. Umieszczanie jakiej wartoci w obiekcie biznesowym za porednictwem
metody set.
37
e wprowadzenie identyfikatora nie rodzi adnych dodatkowych komplikacji. (Przykadowo, operacje porwnywania dwch obiektw klasy Employee musz teraz uwzgldnia pole ID, zatem konieczne bdzie zmodyfikowanie kodu zawierajcego takie operacje). Gdyby zawar identyfikator pracownika w ramach klasy Name, mgby unikn
tego typu problemw. Obiekty tej klasy byyby po prostu wywietlane w nowy sposb.
Dwa obiekty klasy Name mona by nawet porwnywa na podstawie informacji na
temat identyfikatora, ale np. kod w postaci fred.compareTo(ginger) lub fred.equals
(ginger) nie wymagaby wprowadzania adnych modyfikacji.
Nie moesz nawet zautomatyzowa procesu aktualizacji (dostosowywania) kodu, poniewa
caa ta funkcjonalno WYSIWYG, o ktrej tak czsto mona przeczyta w materiaach marketingowych, ukrywa proces generowania kodu. Jeli automatycznie modyfikujesz kod wygenerowany przez komputer, wprowadzone zmiany zostan utracone
w momencie, w ktrym kto inny uyje tego samego generatora. Nawet jeli jeste pewien, e narzdzie to nie zostanie ponownie zastosowane, modyfikowanie wygenerowanego kodu jest zawsze ryzykowne, poniewa wikszo narzdzi z rodziny Visual
Basica wykazuje bardzo niewiele tolerancji dla kodu wygldajcego inaczej ni ten,
ktry zazwyczaj generuj. A jeli Twoje modyfikacje bd polegay na wprowadzeniu
jakich nieoczekiwanych elementw, stosowane narzdzie moe si pogubi do tego
stopnia, e odmwi wykonywania na tym kodzie wszelkich dalszych operacji wtedy,
gdy bdziesz tego naprawd potrzebowa. Co wicej, automatycznie generowany kod
zwykle jest do kiepski, poniewa tworzce go narzdzia nie uwzgldniaj takich
czynnikw jak efektywno, zwizo, czytelno itp.
Bodaj najwiksz wad architektury MVC jest koncepcja kontrolki siatki powizanej
z danymi (ang. data-bound grid control), czyli takiego formantu-tabeli, ktry reprezentuje jednoczenie kod jzyka SQL potrzebny do wypenienia jego komrek zawartoci bazy danych. Co si dzieje, kiedy sownik danych ulega zmianie? Ot cay ten
osadzony kod SQL-a nadaje si wwczas do kosza lub przynajmniej wymaga zasadniczych modyfikacji. Bdziesz musia dokadnie przeanalizowa wszystkie te okna swojego systemu, ktre zawieraj kontrolki powizane z danymi i modyfikowa je za pomoc
swojego wizualnego narzdzia. Zastosowanie architektury trjwarstwowej, w ktrej
warstwa interfejsu uytkownika komunikuje si z warstw zawierajc kod jzyka SQL,
a ta z kolei wsppracuje z warstw bazy danych, nie tylko nie rozwie problemu,
ale wrcz pogorszy Twoj sytuacj, poniewa kod, ktry bdziesz musia zmodyfikowa
zostanie dodatkowo rozproszony pomidzy warstwy. Tak czy inaczej, jeli do budowy
warstwy rodkowej wykorzystasz automatyczny generator kodu (co w dzisiejszych czasach jest zjawiskiem powszechnym), to przydatno tej warstwy z punktu widzenia osb
odpowiedzialnych za konserwacj kodu bdzie minimalna.
Cae to zamieszanie zwizane z koniecznoci rcznego modyfikowania wszystkich okien
przynajmniej dla mnie stanowi wystarczajcy argument, by nie stosowa tego typu
rozwiza. Jakiekolwiek oszczdnoci czasowe wynikajce ze stosowania generatora
kodu prdzej czy pniej zostan zrwnowaone przez znacznie wysze koszty konserwacji systemu.
Systemy tego typu przycigaj programistw przede wszystkim tym, e s konstruowane
za pomoc znanych im technik. Generatory kodu uatwiaj programowanie w nieznanym
jzyku obiektowym, oferujc przyjazne lub wrcz intuicyjne mechanizmy proceduralne.
38
39
4. Terminal ATM formuuje kolejne zapytanie; tym razem ma ono posta: podaj
40
ATM z wykorzystaniem technik obiektowych, a wic traktujc cay system jak zbir
wsppracujcych obiektw, ktre oferuj okrelone zdolnoci (moliwo wykonywania
pewnych czynnoci). Pierwszym krokiem kadego procesu projektowania obiektowego
jest sformuowanie definicji problemu, czyli prezentacji problemu, ktry prbujemy
caociowo rozwiza w ramach czego, co nazywa si czsto dziedzin problemu.
W tym przypadku dziedzin problemu jest bankowo. Definicja problemu opisuje sam
problem, nie program komputerowy. Analizowany problem mona opisa w nastpujcy sposb:
Klient przychodzi do banku, bierze od kasjera w okienku blankiet potwierdzenia
wypaty i wypenia go, wpisujc numer rachunku i kwot wypaty. Klient wraca
do kasjera, potwierdza swoj tosamo i przekazuje wypeniony dokument.
(Kasjer weryfikuje tosamo klienta, sprawdzajc zapisy rejestru bankowego).
Nastpnie kasjer zwraca si o odpowiednie upowanienie do urzdnika bankowego
i wypaca pienidze klientowi.
Dysponujc nawet tak prost definicj problemu, moesz bez trudu zidentyfikowa kilka
potencjalnych kluczowych abstrakcji (klas) wraz z odpowiednimi operacjami (patrz
tabela 1.2). W tym celu posu si formatem karty CRC stworzonym przez Warda Cunninghama (ktry szczegowo omwi w dalszej czci tego rozdziau).
Tabela 1.2. Udziaowcy przypadkw uycia wymienieni w formacie karty CRC
Klasa
Odpowiedzialno
Obiekty wsppracujce
Rejestry bankowe
Urzdnik bankowy
Kasjer: da upowanienia
Potwierdzenie wypaty
Kasjer
41
zapewne nie definiujesz si jako cz banku, ktrego jeste klientem). Obiektowy system terminali ATM modeluje tylko przedstawion wczeniej definicj problemu. Oto
przewidywany przepyw komunikatw:
1. Bill podchodzi do terminala ATM, wkada swoj kart, podaje kod PIN i wydaje
42
Automat komrkowy
Rozszerzmy teraz nasze wyobraenie koncepcji obiektowej w taki sposb, aby obejmowao pojcie interfejsu posu si kolejnym przykadem, ktry wybrukuje drog do
zrozumienia programu Gra w ycie (ang. The Game of Life), z ktrego bdziemy korzysta w dalszej czci tej ksiki.
Dobrym przykadem naturalnego systemu obiektowego jest klasa programw nazywana
automatem komrkowym. Tego typu programy rozwizuj skomplikowane problemy
w sposb bardzo obiektowy ogromny problem jest rozwizywany przez zbir maych,
identycznych obiektw (komrek), z ktrych kady implementuje prosty zbir regu
i komunikuje si ze swoimi bezporednimi ssiadami. Poszczeglne komrki nie maj
co prawda adnej wiedzy o wikszym problemie, ale komunikuj si z innymi komrkami w taki sposb, e z ich perspektywy problem ten rozwizuje si sam.
Typowym przykadem automatu komrkowego jest modelowanie ruchu ulicznego (ktrego omwienie znacznie wykraczaoby poza zakres tematyczny tej ksiki). Problem
przewidywania ruchu ulicznego jest wyjtkowo trudny jest klasycznym problemem
teorii chaosu. Tak czy inaczej, warto pamita, e mona modelowa ruch pojazdw
w taki sposb, by obserwacja jego symulacji umoliwiaa przewidywanie pewnych zdarze
wycznie na podstawie zachowania badanego modelu. Przewidywanie i symulowanie
ruchu ulicznego to oczywicie dwa rne problemy automaty komrkowe sprawdzaj
si doskonale wanie w symulowaniu z pozoru chaotycznych procesw.
Powic kilka kolejnych stron na omawianie problemu ruchu ulicznego nie tylko dlatego, e problem ten tak dobrze demonstruje mechanizm automatw komrkowych,
ale take dlatego, e przykad ten doskonale ilustruje wiele podstawowych zagadnie
43
2. Przeka mi N samochodw.
car[] giveMeCars(int n)
Ssiadujce odcinki drogi komunikuj si w bardzo prosty sposb. Kiedy biecy odcinek decyduje, e musi si pozby kilku samochodw, pyta odcinek ssiadujcy, czy ten
moe je przyj (pierwszy komunikat). Zapytany odcinek moe te samochody przyj
prosi o ich przekazanie ssiedni odcinek, ktry zainicjowa konwersacj (drugi komunikat).
44
Z podobn komunikacj dwustronn bdziemy mieli do czynienia w rozdziale 3. Pocztkowe danie musi zawiera referencj do generujcego je obiektu Road, ktr docelowy obiekt Road bdzie mg wykorzysta podczas dania kolejnych samochodw;
w przeciwnym razie obiekt docelowy nie wiedziaby, ktry odcinek rdowy nadesa
dane danie. Odcinek (fragment drogi) w rodku takiego bloku komunikuje si z dwoma ssiadami (z dwoma przylegajcymi odcinkami drogi, obiektami Road), obiekt reprezentujcy skrzyowanie ma czterech bezporednich ssiadw itd. (Odpowiednie poczenia s ustawiane w momencie tworzenia sieci ulic i mog by implementowane
w formie argumentw konstruktora).
Odcinek drogi (obiekt Road) musi wewntrznie wykorzystywa kilka regu, na bazie
ktrych bdzie decydowa, kiedy moe przyj kolejne samochody. Przykadowo, rednia
efektywna prdko samochodu (obiektu Car), czyli rnica pomidzy momentem wjazdu
samochodu na reprezentowany odcinek a momentem opuszczenia tego odcinka, moe
by funkcj natenia ruchu liczby samochodw przebywajcych na danym odcinku.
Rne typy drg (autostrady, uliczki itp.) mog implementowa te reguy w zrnicowany
sposb. Reguy te s jednak znane tylko obiektom Road. Podobnie jak w przypadku
wszystkich innych systemw obiektowych, tego typu reguy mog by zasadniczo zmieniane bez wpywu na otaczajcy kod, poniewa modyfikacje regu nie bd wpyway
na ksztat interfejsu odcinka drogi (obiektu Road).
45
Take w tym przypadku obiektu Road nie interesuje sposb generowania odpowiedzi
przez obiekt Car na tak postawione pytanie wane jest tylko uzyskanie odpowiedniej
odpowiedzi. W fazie diagnozowania kodu mona wymusi na metodzie obsugujcej ten
komunikat wywietlanie zapytania na konsoli i wykonywanie wpisywanych polece.
Rzeczywisty system bdzie oczywicie wymaga zautomatyzowanego rozwizania, ale
zmiana rcznego funkcjonowania klasy Car na dziaanie automatyczne bdzie wymagaa
zmodyfikowania tylko tej jednej klasy nie bdzie to miao wpywu na reszt systemu.
Warto zwrci uwag na fakt, e obiekt Car nie musi dokadnie wiedzie, gdzie si
znajduje (przypomina to troch rzeczywist sytuacj, ktr modelujemy). Inaczej jest
w przypadku obiektu Road, ktry zna swoje pooenie (obiekt Location), zatem to wanie
obiekt Road przekazuje obiekt Location obiektowi Car. Poniewa obiekt Location stale
si zmienia, obiekt Car nawet nie prbuje tego obiektu wewntrznie utrwala. Obiekt Car
musi zawiera tylko jeden atrybut reprezentujcy cel podry.
Obiekt Car musi dysponowa mechanizmem, ktry umoliwi mu odpowiadanie na pytanie o kierunek jazdy, powinnimy wic stworzy jeszcze jeden obiekt: Map. Obiekt
ten bdzie implementowa jeszcze jeden interfejs przesyania komunikatw.
2. Jestem tutaj i chc jecha tam; w ktrym kierunku powinienem si uda?
Direction whichWayShouldITurn(Location here, Location there)
Obiekt Car, ponownie, nie ma wiedzy na temat techniki udzielania odpowiedzi na zadane
pytanie przez obiekt mapy wystarcza mu samo uzyskiwanie potrzebnych informacji.
(Problem wyboru trasy jest najtrudniejsz czci tego systemu, ale zosta ju rozwizany
przez wszystkie dostpne na rynku urzdzenia nawigacyjne oparte na systemie GPS.
Oznacza to, e odpowiednie rozwizanie mona po prostu kupi). Warto zwrci uwag
na sposb przekazywania pooenia (na podstawie obiektu Map) samochodu do reprezentujcego go obiektu Car. Proces ten, nazywany delegacj, jest typowym rozwizaniem w systemach obiektowych. Obiekt rozwizuje pewien problem, delegujc go do
zawieranego przez siebie obiektu i przekazujc tam wszelkie niezbdne informacje
z zewntrz. Komunikaty przekazywane przez obiekt delegujcy do obiektu delegowanego s zwykle opatrywane dodatkowymi argumentami.
46
Ostatnim elementem tej ukadanki jest okrelenie sposobu, w jaki samochody trafiaj na
drog (obiekt Road). Z punktu widzenia systemu modelujcego ruch uliczny, prawdziwym kocem drogi jest dom kierowcy (nazywany wjazdem). Podobnie, miejsce pracy
kierowcy take moe stanowi obiekt Road (nazwany parkingiem). Obiekty domu i miejsca pracy musz nie tylko implementowa interfejs Road, ale take zna odcinki drogi,
z ktrymi te obiekty s poczone. Przydomowy gara i parking w miejscu pracy powinny
te wiedzie, jak wypuszcza samochody do systemu i akceptowa ich przyjmowanie
o okrelonych porach dnia implementacja tego elementu bdzie prosta, poniewa
bdzie wymagaa jedynie uycia odpowiedniego interfejsu obiektw Road.
Dodajmy teraz interfejs uytkownika. Klasyczne wymaganie odnonie do systemw
obiektowych mwi, e obiekt nie powinien ujawnia szczegw swojej implementacji.
Naszym celem jest maksymalizacja moliwoci konserwacji tworzonego oprogramowania. Jeli wszystkie informacje na temat implementacji s zazdronie strzeonym sekretem obiektu, ewentualne zmiany tej implementacji nie bd miay wpywu na funkcjonowanie kodu wykorzystujcego dany obiekt. Oznacza to, e modyfikacja implementacji
pojedynczego obiektu nie wywraca reszty systemu. Poniewa wszystkie zmiany koncentruj si zwykle wok definicji pojedynczej klasy, konserwacja systemw obiektowych jest wyjtkowo atwa, ale tylko wtedy, gdy zachowana jest zasada hermetycznoci. (W niektrych sytuacjach mog istnie istotne przesanki do rezygnacji z tej reguy,
jednak decyzja w tym zakresie powinna by podejmowana z uwzgldnieniem przyszych
utrudnie w konserwacji systemu).
Wymaganie hermetycznoci oznacza, e dobrze zaprojektowany obiekt bdzie przynajmniej w jakim stopniu odpowiada za tworzenie wasnego wycinka interfejsu uytkownika. Oznacza to, e dobrze zaimplementowana klasa nie bdzie udostpniaa metod
zwracajcych i ustawiajcych jej pola, poniewa takie metody stanowiyby furtk do
szczegw implementacji, a wic w konsekwencji prowadziy do powanych problemw w zakresie konserwacji systemu zbudowanego na ich bazie. Jeli implementacja
obiektu zostanie zmodyfikowana w taki sposb, e niezbdna bdzie zmiana np. typu
lub zakresu wartoci zwracanych przez tego typu metod, bdziesz musia przebudowa nie tylko obiekt definiujcy t metod, ale take cay kod, ktry z niej porednio
lub bezporednio korzysta. Wicej uwagi temu zagadnieniu oraz technikom projektowania systemw bez metod zwracajcych i ustawiajcych powic za chwil.
W biecym systemie moemy zbudowa interfejs uytkownika, dodajc pojedyncz
metod do interfejsu Road.
3. Narysuj swoj reprezentacj wzdu tej linii:
drawYourself(Graphics g, Point begin, Point end);
Interfejs uytkownika obiektw Road wywietla redni prdko samochodw na reprezentowanym odcinku drogi (ktry moe si rni w zalenoci od natenia ruchu)
za pomoc zmieniajcych si kolorw rysowanych linii. W wyniku zastosowania tego
mechanizmu powinnimy otrzyma plan miasta, na ktrym kolory ulic bd wskazyway
na przewidywan prdko pokonywania poszczeglnych odcinkw. Obiekt Map musi
oczywicie wiedzie o wszystkich obiektach Road, aby waciwie kierowa procesem
wizualizacji planu i w razie koniecznoci delegowa dania rysowania do poszczeglnych obiektw Road. Poniewa obiekty te same odpowiadaj za swoj wizualizacj, nie
47
ma potrzeby tworzenia mnstwa metod zwracajcych i proszenia ich o informacje niezbdne dla zewntrznych generatorw interfejsu uytkownika przykadowo, taka
metoda jak getAverageSpeed() bdzie zupenie zbdna.
Teraz, kiedy ju wykonalimy podstawowe zadania, moemy wprawi nasz system
w ruch. Musimy wiza ze sob wszystkie drogi, wjazdy i parkingi za kadym razem,
gdy kompilujemy nasz system. Musimy te umieci w tym systemie kilka pojazdw
(take w czasie kompilacji) i rozpocz obserwacj przygotowanego modelu. Z kadym
tykniciem zegara wszystkie odcinki drg decyduj o liczbie samochodw, ktrych
musz si pozby, i przekazuj je do ssiednich odcinkw. Kady odcinek (obiekt Road)
automatycznie aktualizuje swj wycinek interfejsu uytkownika, aby odzwierciedla
obserwowane zmiany redniej prdkoci. Voil! Mamy model ruchu ulicznego.
Kiedy ju zaprojektujesz system przesyania komunikatw, staniesz przed koniecznoci
wycignicia waciwych wnioskw z diagramu modelu statycznego. Ewentualne powizania wystpuj wycznie pomidzy klasami, ktrych obiekty wzajemnie si komunikuj definiowane s tylko naprawd potrzebne komunikaty. Na rysunku 1.3 przedstawiono odpowiedni diagram UML. Warto pamita, e rozpoczcie projektowania od
tworzenia i analizy takiego diagramu byoby strat czasu. Zanim zrozumiesz relacje pomidzy klasami, musisz przecie wiedzie, jaki powinien by przepyw komunikatw.
Rysunek 1.3.
Diagram modelu
statycznego UML
dla systemu
modelujcego
ruch uliczny
Jeli chcesz zdoby dowiadczenie w zakresie eksperymentowania z tego typu symulatorami ruchu ulicznego, powiniene si przyjrze popularnej grze SimCity firmy Maxis
Software. Poniewa nie widziaem kodu rdowego tego programu, tak naprawd nie
wiem, czy SimCity rzeczywicie zaimplementowano w formie automatu komrkowego,
bybym jednak zdumiony, gdyby okazao si, e jest inaczej. Pewne jest, e na poziomie
interfejsu uytkownika gra SimCity dziaa podobnie jak nasz system modelowania ruchu
ulicznego. Maxis oferuje darmow wersj tego produktu (zatytuowan SimCity Classic)
na swojej witrynie internetowej (patrz http://www.maxis.com).
48
49
Money a, b, c;
//
a.setValue( b.getValue() * c.getValue() );
50
51
52
Zamiast tego zadaj od obiektu klasy Money wykonania odpowiednich dziaa za Ciebie:
Money a, b, c;
//
a.increaseBy( b );
Nie mwisz ju: daj mi ten atrybut, abym mg go wywietli. Teraz dasz czego
zupenie innego: daj mi moliw do wywietlenia wizualizacj tego atrybutu lub
wywietl swoj zawarto.
Kolejnym wyznacznikiem realizacji tej reguy jest szczegowo operacji. Operacje obszerne sprowadzaj si do jednorazowego dania od obiektw wykonania duych zada.
Szczegowe operacje daj od obiektw realizacji stosunkowo niewielkich zada. Oglnie, wol obszerne metody, poniewa ich stosowanie upraszcza kod i w wielu przypadkach eliminuje konieczno stosowania metod zwracajcych i ustawiajcych.
Metody akcesorw i mutatorw mona eliminowa dopiero na etapie budowy modelu
systemu, poniewa bez dobrze przemylanego modelu dynamicznego wiarygodne
przewidywanie przyszych mechanizmw komunikacji obiektw klas jest po prostu
niemoliwe. Oznacza to, e w przypadku braku tego modelu musisz zapewnia jak najwicej technik udostpniania danych, poniewa nie jeste w stanie przewidzie, ktre
z tych technik faktycznie bd konieczne. Taka strategia projektowania przez zgadywanie jest w najlepszym przypadku nieefektywna, poniewa w praktyce oznacza strat
czasu na pisanie niepotrzebnych metod (lub dodawanie zbdnych mechanizmw do implementowanych klas). Jeli postpujesz w myl zasady, e w pierwszej kolejnoci naley budowa model statyczny, musisz by przygotowany na to, e stracisz mnstwo
czasu na tworzenie nieprzydatnych lub zbyt elastycznych metod. Co wicej, jeli niewaciwy model statyczny wymusi zbyt due nakady na tworzenie niepotrzebnych rozwiza, cay projekt moe si zakoczy niepowodzeniem; a jeli mimo to zdecydujesz si
na jego kontynuowanie, koszt konserwacji kodu bdzie przewysza koszt jego ponownego napisania. Wrmy teraz do przykadu modelowania ruchu ulicznego, w ktrym
uyem modelu statycznego do analizy relacji odkrytych w fazie planowania systemu
przesyania komunikatw. Nie projektowaem modelu statycznego, by pniej prbowa na jego podstawie budowa model dynamiczny (z uwzgldnieniem ogranicze narzuconych przez przygotowany wczeniej model statyczny).
Uwane projektujc i skupiajc si na tym, co chcesz osign (nie na tym, jak to
zrobi), moesz wyeliminowa ze swojego programu znaczn cz metod zwracajcych
i ustawiajcych.
53
samochody. Skoro obiekty klasy Road same odpowiadaj za swoj reprezentacj graficzn, wszystkie te zmiany powinny dotyczy wycznie definicji tej klasy. Co wicej,
rne typy obiektw klasy Road (np. parkingi) mog realizowa zadanie wizualizacji
w rny sposb. Wad takiego rozwizania jest oczywicie zamieszanie w samej klasie
Road, ale cay kod zwizany z obsug interfejsu uytkownika mona skupi w jednej
klasie wewntrznej, aby zapewni przejrzysto systemu.
Warto te pamita, e aden kod interfejsu uytkownika tak naprawd nie zosta umieszczony w logice biznesowej systemu. Do opracowania warstwy interfejsu uytkownika
uyem podsystemu AWT lub Swing oba stanowi dodatkowe warstwy abstrakcyjne.
Waciwy kod interfejsu znajduje si wic w implementacji tych podsystemw. Na
tym wanie polega zaleta warstw abstrakcyjnych umoliwia izolowanie logiki biznesowej od odpowiednich mechanizmw podsystemu. Mog atwo przenie swj
system do innego rodowiska graficznego bez koniecznoci zmiany kodu, zatem jedynym problemem jest skomplikowany kod. Z tym utrudnieniem mog sobie poradzi,
umieszczajc wszystkie operacje zwizane z wizualizacj obiektw w wewntrznej klasie
(lub stosujc wzorzec fasady, ktry omwi za chwil).
Warto pamita, e tylko najprostsze klasy mog obsugiwa swoj wizualizacj za pomoc pojedynczej metody drawYourself(). W wikszoci przypadkw programista bdzie potrzebowa wikszej kontroli. Zdarza si, e te same obiekty musz prezentowa
swoj zawarto na wiele sposobw (jzyk HTML, kontrolka JLabel podsystemu Swing
itp.); rwnie czsto bdziesz musia wizualizowa tylko kilka spord wielu atrybutw obiektu.
Co wicej, izolacja implementacji obiektu od reszty programu wcale nie wymaga fizycznego rysowania reprezentowanych przez ten obiekt danych na ekranie. Tak naprawd
potrzebujesz jedynie jakiego uniwersalnego (przynajmniej na poziomie programu) mechanizmu graficznego reprezentowania danych. Obiekt moe np. przekazywa wizualizacj swoich danych w formie dokumentu XML do podsystemu wywietlania. Klasa
pomocnicza uyta wraz z wyraeniami java.text.NumberFormat moe przeksztaca t
reprezentacj zgodnie z okrelonymi ustawieniami regionalnymi. Wspominana klasa
Money moe zwraca w formacie Unicode odpowiedni wizualizacj acucha (obiektu
klasy String), ktra bdzie czya kwot pienin z symbolem waluty. Mona nawet
zwraca obraz w formacie .gif lub kontrolk JLabel.
Zmierzam do tego, e jeli reprezentacje tych atrybutw s obsugiwane w sposb waciwy, moliwe jest modyfikowanie wewntrznych mechanizmw klasy bez koniecznoci dostosowywania kodu uywajcego tych reprezentacji. (Reprezentacj jakiego
obiektu bd atrybutu, ktra jest prezentowana w sposb umoliwiajcy wywietlanie,
ale nie modyfikowanie, mona traktowa jak pewn odmian wzorca memento patrz
dalsza cz tego rozdziau. Istnieje te moliwo wykorzystywania innych wzorcw
projektowych, w szczeglnoci wzorca budowniczego, do wymuszania na obiektach
samodzielnego prezentowania swoich danych i jednoczenie izolowania kodu tworzcego interfejs uytkownika od waciwych obiektw. Wicej informacji na temat tego
wzorca znajdziesz w rozdziale 4.).
54
JavaBeans i Struts
Ale moesz protestowa co z JavaBeans, Struts i innymi bibliotekami, ktre
wykorzystuj przecie zarwno akcesory, jak i mutatory? No wanie, co z nimi?
Istnieje doskonay sposb budowy komponentw JavaBean bez metod zwracajcych
i ustawiajcych wanie w tym celu stworzono klasy BeanCustomer, BeanInfo i BeanDescriptor. Projektanci specyfikacji komponentw JavaBean uwzgldnili metody get
i set tylko dlatego, e sdzili, i uatwi to przygotowywanie komponentw niedowiadczonym programistom (mieli nadziej, e tacy programici bd mogli tworzy komponenty i jednoczenie uczy si, jak naley to robi prawidowo). Przewidywania
twrcw tej technologii niestety si nie sprawdziy.
Ludzie maj skonno do nadmiernego przywizywania si do biblioteki JavaBeans
(i wszelkich innych bibliotek wykorzystujcych jakie elementy proceduralne). Programici zdaj si zapomina, e biblioteki te pocztkowo opracowywano z myl o rozwizywaniu konkretnych problemw napotykanych przez programistw. Niektrzy programici s szczeglnie zwizani z technikami programowania proceduralnego, inni nie
mog zapomnie o technikach obiektowych. Cz projektantw celowo ogupia
swoje interfejsy, poniewa wie, e w przeciwnym razie wielu ludzi po prostu by tych
interfejsw nie zrozumiao.
Przykadem takiego wanie podejcia s metody get i set zastosowane w technologii
JavaBeans. Metody te wprowadzono wycznie w celu zapewnienie dostpu do pewnych
waciwoci midzy innymi z poziomu narzdzi budowania interfejsw uytkownika.
Projektanci tej biblioteki nie przypuszczali, e programici bd te metody wywoywali
samodzielnie. Jedynym celem ich zdefiniowania byo umoliwienie interfejsom API
introspekcji klasy Class, sprawdzanie istnienia poszczeglnych waciwoci (w ramach zautomatyzowanych narzdzi, w tym rodowisk implementowania interfejsw
uytkownika) na podstawie analizy samych nazw metod. Takie podejcie nie sprawdzio
si w praktyce. Wraz z metodami zwracajcymi i ustawiajcymi wprowadzono do definicji klas mnstwo niepotrzebnego kodu, ktry uczyni ca technologi zdecydowanie
zbyt skomplikowan i zbyt proceduraln. Programici, ktrzy nie rozumieli idei abstrakcji danych, wywoywali te metody, powodujc, e kod tworzony na podstawie biblioteki
JavaBeans sta si niezwykle trudny w konserwacji. Midzy innymi z tego wzgldu
w wersji 1.5 Javy wprowadzono mechanizm metadanych, dziki ktremu mona
wyeliminowa z kodu nastpujce wyraenia:
private int property;
public int getProperty (
){ return property; }
public void setProperty (int value){ property = value; }
Narzdzia wspomagajce budow interfejsw uytkownika mog teraz uywa interfejsw API introspekcji do odnajdywania waciwoci zamiast analizowa nazwy metod i na ich podstawie wnioskowa o istnieniu lub braku waciwoci o okrelonej nazwie.
Co wicej, nowy mechanizm eliminuje konieczno zamiecania kodu metodami akcesorw.
55
Dostrajanie
Syszaem jeszcze jeden argument przemawiajcy za stosowaniem metod akcesorw
i mutatorw, zgodnie z ktrym takie rodowiska programowania jak Eclipse i pokrewne
do tego stopnia uatwiaj dostrajanie definicji metod do zwracania okrelonych typw,
e w praktyce nie ma si czym przejmowa. Ja jednak nadal si przejmuj.
Po pierwsze, mechanizm dostrajania kodu w rodowisku Eclipse obejmuje tylko istniejcy projekt. Jeli wic Twoja klasa jest wykorzystywana w wielu projektach, bdziesz
musia dostroi kady z nich osobno. Firmy, ktre prawidowo korzystaj z techniki
wielokrotnego uywania gotowych klas, zatrudniaj zwykle wiele grup programistw
pracujcych rwnolegle nad rnymi projektami programici z poszczeglnych zespow nie bd zadowoleni, kiedy powiesz im o daleko idcych zmianach w kodzie wspuytkowanej klasy, wynikajcych z jakiej, skdind susznej, obserwacji.
Po drugie, automatyczne dostrajanie sprawdza si tylko w przypadku stosunkowo niewielkich i prostych zmian, nie jest wic waciwym rozwizaniem w przypadku powanych modyfikacji. Konsekwencje takich zmian s zwykle zbyt rozlege, aby mogo sobie
z nimi poradzi zautomatyzowane narzdzie. Moesz np. zmieni skrypty jzyka SQL
i porednio wpyn na metody wywoywane w otoczeniu zmodyfikowanych skryptw.
I wreszcie po trzecie, warto jeszcze raz odnie si do wspomnianych zmian w klasie
Money i polu System.out. Prosta modyfikacja typw kilku zwracanych wartoci nie
wystarczy do waciwej obsugi omwionych przeze mnie zmian. Konieczna bdzie
przebudowa kodu otaczajcego wywoania odpowiednich metod zwracajcych. Trudno
oczywicie dowie, e dostrajanie kodu jest czym zym, moesz sam si przekona,
e zmian, o ktrych mwi po prostu nie da si wprowadzi za pomoc zautomatyzowanego narzdzia.
56
57
Odpowiedzialno
58
Pierwszy cykl opracowywania kart CRC zawsze jest obarczony powanymi bdami
pewne czynniki bd jeszcze ulegay zmianie.
W czasie swoich zaj Beck i Cunningham prezentowali przypadek uycia i namawiali
suchaczy do odgadywania, ktre obiekty bd wymagane do realizacji opisanego scenariusza. Analiza rozpoczynaa si zwykle od dwch obiektw, do ktrych z czasem
dodawano kolejne w odpowiedzi na demonstrowany rozwj scenariusza. Uczestnicy
wicze byli wyznaczani do roli poszczeglnych obiektw i otrzymywali kopie przypisanych im kart CRC. Jeli niezbdne byo uycie wielu obiektw pojedynczej klasy,
wyznaczano wiele osb (po jednej dla kadego z tych obiektw). Studenci dosownie
wystawiali sztuk opart na przypadku uycia. Oto kilka regu, ktrych staram si
przestrzega podczas gry w przypadku uycia z kartami CRC:
Wykonuj czynnoci odpowiadajce roli danego obiektu w przypadku uycia,
59
Opisany przeze mnie proces tak naprawd jest procesem projektowania obiektowego,
tyle e uproszczonym na potrzeby rodowiska zaj dydaktycznych. Niektrzy projektuj nawet rzeczywiste programy z wykorzystaniem kart CRC, ale technika ta nie sprawdza si w przypadku wikszych, niebanalnych rozwiza. Znacznie czciej projektanci
buduj modele dynamiczne i statyczne w jzyku UML, stosujc ktry z formalnych
procesw (RUP, Crystal, a nawet pewne odmiany Extreme Programming). Kluczowe znaczenie ma fakt, i system obiektowy jest w istocie konwersacj pomidzy obiektami. Jeli
przez chwil si nad tym zastanowisz, dojdziesz do przekonania, e metody get i set
najzwyczajniej w wiecie nie s potrzebne w takiej konwersacji. Z tego samego wzgldu
metody get i set nie powinny wystpowa w Twoim kodzie, jeli przed przystpieniem
do jego budowy przeprowadzie proces projektowania z naleyt starannoci.
Tak dugo, jak dugo to tylko moliwe modelowanie nie powinno wykracza poza dziedzin problemu (zgodnie z tym, o czym wspomniaem w ostatniej regule). Tym, co wpdza wikszo ludzi w kopoty jest przekonanie o modelowaniu dziedziny w czasie,
gdy tak naprawd proces modelowania ma miejsce na poziomie implementacji. Jeli Twj
system przesyania komunikatw nie korzysta ze sownictwa typowego dla danej dziedziny problemu jeli Twj jzyk nie jest zrozumiay dla przecitnego uytkownika
tego programu to tak naprawd modelujesz ten system na poziomie implementacji.
W takich rodowiskach jak komputery (lub, co gorsza, bazy danych lub narzdzia wspomagajce budow interfejsw uytkownika) nie ma miejsca na ten poziom modelowania.
Przykadowo, w modelowaniu CRC wymagane jest utrzymywanie konwersacji w obszarze dziedziny problemu wanie przez stosowanie takiego sownictwa i procesw, ktrymi
posugiwaliby si prawdziwi uytkownicy kocowi. W ten sposb mona zapewni wierne
odwzorowanie modelowanej dziedziny przez system przesyania komunikatw. Baza
danych jest tylko elementem wewntrznym, ktry jest wykorzystywany przez niektre
klasy w roli mechanizmu utrwalania danych, i ktry w ogle nie powinien wystpowa w pocztkowym modelu.
Jeli utrzymasz struktur komunikatw w obszarze dziedziny problemu, najprawdopodobniej uda Ci si wyeliminowa zdecydowan wikszo metod get i set, poniewa
tego typu polecenia po prostu nie wystpuj w komunikacji pomidzy ekspertami w danej
dziedzinie, ktrzy rozwizuj rzeczywiste problemy.
60
61
62
Przeanalizujmy teraz dostpn w Javie klas Color. Kiedy ju utworzysz obiekt tej klasy,
nie moesz zmieni reprezentowanego przez niego koloru, poniewa klasa Color nie udostpnia adnych metod zmieniajcych kolor. Przyjrzyj si nastpujcemu fragmentowi:
public static final Color background = Color.RED;
//
c.darken();
Wywoanie metody darken() nie modyfikuje obiektu wskazywanego przez sta background; zamiast tego metoda zwraca obiekt klasy Color, ktrego odcie jest ciemniejszy od
koloru oryginalnego. Powyszy kod tak naprawd niczego nie robi, poniewa zwrcony obiekt klasy Color nie jest nigdzie umieszczany, zatem nie moesz teraz wykona
operacji:
background = c.darken();
63
konserwacji kodu. Zanim dodasz do definicji klasy metod akcesora lub mutatora,
upewnij si, e jest ona rzeczywicie niezbdna.
Klasy, ktre bezporednio modeluj system na poziomie dziedzinowym
bazy danych, klas obsugujcych interfejs uytkownika itp.), tym trudniej Ci bdzie
ukry szczegy implementacyjne swojego kodu. Rozwanym posuniciem jest
w takim przypadku uycie akcesorw i mutatorw w specjalnie utworzonej
warstwie granicznej.
Take uniwersalne biblioteki i klasy nie mog w peni ukrywa swoich
64
65
pyw danych jest rzeczywicie konieczny. Czy moesz tak zmodyfikowa system przesyania komunikatw, aby informacje byy przekazywane w formie mniej szczegowych
struktur, co mogoby wyeliminowa ten tryb przenoszenia danych? Czy moesz przekazywa te same informacje w postaci argumentw komunikatw, zamiast w postaci
osobnych komunikatw? Czy alternatywna architektura rzeczywicie umoliwi lepsze
ukrywanie implementacji? Jeli jednak nie ma alternatywy dla istniejcego rozwizania,
musisz si z tym pogodzi.