Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00092 008453 10460882 na godz. na dobę w sumie
Ruby. Wzorce projektowe - książka
Ruby. Wzorce projektowe - książka
Autor: Liczba stron: 368
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-1688-6 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> ruby - programowanie
Porównaj ceny (książka, ebook (-82%), audiobook).

Zwiększ elastyczność swojego kodu dzięki wzorcom projektowym!

Stworzony w 1995 roku przez Yukihiro Matsumoto język Ruby dzięki swym unikalnym możliwościom zdobywa serca programistów na całym świecie. Cechy, które podbijają to nieufne środowisko, to między innymi prosta składnia z wbudowanymi w nią wyrażeniami regularnymi, automatyczne oczyszczanie pamięci i wiele, wiele innych. Ogromna i chętna do pomocy społeczność czyni to rozwiązanie jeszcze bardziej atrakcyjnym. Ruby pozwala na korzystanie ze wzorców projektowych - zbioru zasad i reguł prowadzących do celu w najlepszy, najszybszy i najbardziej elastyczny sposób.

Wzorce projektowe kojarzą się głównie z językami Java oraz C i C++. Książka 'Ruby. Wzorce projektowe' pokazuje, że można ich z powodzeniem używać również w języku Ruby. Dowiesz się z niej, w jaki sposób wykorzystać znane wzorce, takie jak Observer, Singleton czy też Proxy. Autor przedstawi Ci również nowe wzorce, które ze względu na cechy języka Ruby mogą zostać w nim zastosowane. Jednak zanim przejdziesz do ich omawiania, Russ poprowadzi Cię przez podstawy programowania w tym języku. Nauczysz się używać między innymi pętli, instrukcji warunkowych, wyrażeń regularnych. Niewątpliwie Twoją ciekawość wzbudzi tak zwany 'duck typing', który oczywiście także został dokładnie tu omówiony. Russ Olsen dzięki swojemu wieloletniemu doświadczeniu każdy wzorzec ilustruje przykładem z życia wziętym. Ułatwi Ci to przyswojenie i zastosowanie we własnych projektach przedstawionych tu wzorców.

Korzystaj z doświadczenia najlepszych programistów - używaj wzorców projektowych w języku Ruby!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Ruby. Wzorce projektowe Autor: Russ Olsen T‡umaczenie: Miko‡aj Szczepaniak ISBN: 978-83-246-1688-6 Tytu‡ orygina‡u: Design Patterns in Ruby (Addison-Wesley Professional Ruby Series) Format: 172x245, stron: 370 ZwiŒksz elastyczno(cid:156)(cid:230) swojego kodu dziŒki wzorcom projektowym! (cid:149) Jak rozpocz„(cid:230) przygodŒ z jŒzykiem Ruby? (cid:149) Jak wykorzysta(cid:230) drzemi„ce w nim mo¿liwo(cid:156)ci? (cid:149) Jak zwiŒkszy(cid:230) elastyczno(cid:156)(cid:230) tworzonego kodu za pomoc„ wzorc(cid:243)w projektowych? Stworzony w 1995 roku przez Yukihiro Matsumoto jŒzyk Ruby dziŒki swym unikalnym mo¿liwo(cid:156)ciom zdobywa serca programist(cid:243)w na ca‡ym (cid:156)wiecie. Cechy, kt(cid:243)re podbijaj„ to nieufne (cid:156)rodowisko, to miŒdzy innymi prosta sk‡adnia z wbudowanymi w ni„ wyra¿eniami regularnymi, automatyczne oczyszczanie pamiŒci i wiele, wiele innych. Ogromna i chŒtna do pomocy spo‡eczno(cid:156)(cid:230) czyni to rozwi„zanie jeszcze bardziej atrakcyjnym. Ruby pozwala na korzystanie ze wzorc(cid:243)w projektowych (cid:150) zbioru zasad i regu‡ prowadz„cych do celu w najlepszy, najszybszy i najbardziej elastyczny spos(cid:243)b. Wzorce projektowe kojarz„ siŒ g‡(cid:243)wnie z jŒzykami Java oraz C i C++. Ksi„¿ka (cid:132)Ruby. Wzorce projektowe(cid:148) pokazuje, ¿e mo¿na ich z powodzeniem u¿ywa(cid:230) r(cid:243)wnie¿ w jŒzyku Ruby. Dowiesz siŒ z niej, w jaki spos(cid:243)b wykorzysta(cid:230) znane wzorce, takie jak Observer, Singleton czy te¿ Proxy. Autor przedstawi Ci r(cid:243)wnie¿ nowe wzorce, kt(cid:243)re ze wzglŒdu na cechy jŒzyka Ruby mog„ zosta(cid:230) w nim zastosowane. Jednak zanim przejdziesz do ich omawiania, Russ poprowadzi CiŒ przez podstawy programowania w tym jŒzyku. Nauczysz siŒ u¿ywa(cid:230) miŒdzy innymi pŒtli, instrukcji warunkowych, wyra¿eæ regularnych. Niew„tpliwie Twoj„ ciekawo(cid:156)(cid:230) wzbudzi tak zwany (cid:132)duck typing(cid:148), kt(cid:243)ry oczywi(cid:156)cie tak¿e zosta‡ dok‡adnie tu om(cid:243)wiony. Russ Olsen dziŒki swojemu wieloletniemu do(cid:156)wiadczeniu ka¿dy wzorzec ilustruje przyk‡adem z ¿ycia wziŒtym. U‡atwi Ci to przyswojenie i zastosowanie we w‡asnych projektach przedstawionych tu wzorc(cid:243)w. (cid:149) Podstawy programowania w jŒzyku Ruby (cid:149) Zastosowanie wzorc(cid:243)w (cid:150) takich jak Observer, Composite, Iterator, Command i wiele innych (cid:149) Wykorzystanie technik metaprogramowania do tworzenia obiekt(cid:243)w niestandardowych (cid:149) Wykorzystanie wyra¿eæ regularnych (cid:149) U¿ycie jŒzyk(cid:243)w dziedzinowych (cid:149) Spos(cid:243)b instalacji jŒzyka Ruby Korzystaj z do(cid:156)wiadczenia najlepszych programist(cid:243)w (cid:150) u¿ywaj wzorc(cid:243)w projektowych w jŒzyku Ruby! Wydawnictwo Helion ul. Ko(cid:156)ciuszki 1c 44-100 Gliwice tel. 032 230 98 63 e-mail: helion@helion.pl SPIS TRE¥CI CZ}¥m I Rozdziaï 1. Rozdziaï 2. Sïowo wstÚpne ..................................................................................................15 Przedmowa ........................................................................................................19 PodziÚkowania ..................................................................................................25 O autorze ............................................................................................................27 WZORCE PROJEKTOWE I RUBY .................................................29 Budowa lepszych programów z wykorzystaniem wzorców projektowych ...................................................................................31 Banda Czworga ................................................................................................. 32 Wzorce dla wzorców ........................................................................................ 33 Oddzielaj elementy zmienne od elementów staïych ...................... 33 Programuj pod kÈtem interfejsu, nie implementacji ....................... 34 Stosuj kompozycjÚ zamiast dziedziczenia ........................................ 36 Deleguj, deleguj i jeszcze raz deleguj ................................................ 40 Czy dane rozwiÈzanie rzeczywiĂcie jest niezbÚdne ........................ 41 CzternaĂcie z dwudziestu trzech .................................................................... 43 Wzorce projektowe w jÚzyku Ruby? ............................................................. 45 Pierwsze kroki w jÚzyku Ruby ......................................................................47 Interaktywny jÚzyk Ruby ................................................................................ 48 Przywitaj siÚ ze Ăwiatem .................................................................................. 48 Zmienne .............................................................................................................. 51 Typy Fixnum i Bignum .................................................................................... 52 Liczby zmiennoprzecinkowe .......................................................................... 53 W jÚzyku Ruby nie ma typów prostych ........................................................ 54 Kiedy brakuje obiektów… ............................................................................... 55 Prawda, faïsz i nil .............................................................................................. 55 Decyzje, decyzje ................................................................................................ 57 PÚtle ..................................................................................................................... 58 8 RUBY. WZORCE PROJEKTOWE WiÚcej o ïañcuchach .......................................................................................... 60 Symbole ............................................................................................................... 63 Tablice ................................................................................................................. 63 Tablice mieszajÈce ............................................................................................. 65 Wyraĝenia regularne ........................................................................................ 65 Nasza pierwsza klasa ........................................................................................ 66 Operacje na zmiennych egzemplarzy ........................................................... 68 Obiekt pyta: Kim jestem? ................................................................................. 70 Dziedziczenie, podklasy i nadklasy ............................................................... 71 Opcje argumentów ........................................................................................... 72 Moduïy ................................................................................................................ 73 WyjÈtki ................................................................................................................ 76 WÈtki ................................................................................................................... 77 ZarzÈdzanie odrÚbnymi plikami z kodem ěródïowym .............................. 78 Podsumowanie .................................................................................................. 79 WZORCE PROJEKTOWE W J}ZYKU RUBY ..................................81 Urozmaicanie algorytmów za pomocÈ wzorca projektowego Template Method .................................83 Jak stawiÊ czoïo typowym problemom .......................................................... 84 Izolowanie elementów zachowujÈcych dotychczasowÈ formÚ ................ 85 Odkrywanie wzorca projektowego Template Method .............................. 88 Metody zaczepienia .......................................................................................... 89 Gdzie siÚ wïaĂciwie podziaïy wszystkie te deklaracje? ............................... 92 Typy, bezpieczeñstwo i elastycznoĂÊ ............................................................. 93 Testy jednostkowe nie majÈ charakteru opcjonalnego ............................... 95 Uĝywanie i naduĝywanie wzorca projektowego Template Method ....... 97 Szablony w praktycznych zastosowaniach ................................................... 98 Podsumowanie .................................................................................................. 99 ZastÚpowanie algorytmu strategiÈ ..............................................................101 Deleguj, deleguj i jeszcze raz deleguj .......................................................... 102 Wspóïdzielenie danych przez kontekst i strategiÚ .................................... 104 Jeszcze raz o kaczym typowaniu .................................................................. 106 Obiekty Proc i bloki kodu .............................................................................. 107 Krótka analiza kilku prostych strategii ........................................................ 111 Uĝywanie i naduĝywanie wzorca projektowego Strategy ....................... 112 Wzorzec Strategy w praktycznych zastosowaniach .................................. 113 Podsumowanie ................................................................................................ 114 Jak byÊ na bieĝÈco dziÚki wzorcowi Observer .........................................117 Trzymamy rÚkÚ na pulsie .............................................................................. 117 Jak skuteczniej trzymaÊ rÚkÚ na pulsie? ...................................................... 119 WyodrÚbnianie mechanizmu umoĝliwiajÈcego obserwacjÚ .................... 122 Stosowanie bloków kodu w roli obserwatorów ......................................... 125 Odmiany wzorca projektowego Observer .............................................. 126 CZ}¥m II Rozdziaï 3. Rozdziaï 4. Rozdziaï 5. SPIS TRE¥CI 99 Rozdziaï 6. Rozdziaï 7. Rozdziaï 8. Rozdziaï 9. Uĝywanie i naduĝywanie wzorca projektowego Observer ..................... 127 Wzorzec Observer w praktycznych zastosowaniach ................................ 129 Podsumowanie ................................................................................................ 130 Budowa wiÚkszej caïoĂci z czÚĂci za pomocÈ wzorca Composite .........133 CaïoĂÊ i czÚĂci ................................................................................................... 134 Tworzenie kompozytów ................................................................................ 136 Doskonalenie implementacji wzorca Composite z wykorzystaniem operatorów .................................................................. 140 A moĝe tablica w roli kompozytu? ............................................................... 141 Kïopotliwe róĝnice .......................................................................................... 141 Wskaěniki w obie strony ................................................................................ 142 Uĝywanie i naduĝywanie wzorca projektowego Composite .................. 143 Kompozyty w praktycznych zastosowaniach ............................................ 145 Podsumowanie ................................................................................................ 147 Przeszukiwanie kolekcji z wykorzystaniem wzorca Iterator ................149 Iteratory zewnÚtrzne ...................................................................................... 149 Iteratory wewnÚtrzne ..................................................................................... 152 Iteratory wewnÚtrzne kontra iteratory wewnÚtrzne ................................ 153 Niezrównany moduï Enumerable ................................................................ 154 Uĝywanie i naduĝywanie wzorca projektowego Iterator ........................ 156 Iteratory w praktycznych zastosowaniach ................................................. 158 Podsumowanie ................................................................................................ 161 Doprowadzanie spraw do koñca za pomocÈ wzorca Command ...........163 Eksplozja podklas ............................................................................................ 164 Prostsze rozwiÈzanie ...................................................................................... 165 Stosowanie bloków kodu w roli poleceñ ..................................................... 166 Rejestrowanie poleceñ .................................................................................... 167 Wycofywanie operacji za pomocÈ wzorca Command .............................. 170 Kolejkowanie poleceñ .................................................................................... 173 Uĝywanie i naduĝywanie wzorca projektowego Command .................. 174 Wzorzec projektowy Command w praktycznych zastosowaniach ........ 175 Migracje w ramach interfejsu ActiveRecord ................................... 175 Madeleine ............................................................................................. 176 Podsumowanie ................................................................................................ 179 Wypeïnianie luk z wykorzystaniem wzorca Adapter .............................181 Adaptery programowe ................................................................................... 182 Minimalne niedociÈgniÚcia ............................................................................ 184 Czy alternatywÈ moĝe byÊ adaptowanie istniejÈcych klas? ..................... 186 Modyfikowanie pojedynczych obiektów .................................................... 187 AdaptowaÊ czy modyfikowaÊ? ..................................................................... 188 Uĝywanie i naduĝywanie wzorca projektowego Adapter ....................... 190 Adaptery w praktycznych zastosowaniach ................................................ 190 Podsumowanie ................................................................................................ 191 10 RUBY. WZORCE PROJEKTOWE Rozdziaï 10. Rozdziaï 11. Rozdziaï 12. Tworzenie zewnÚtrznego reprezentanta naszego obiektu z wykorzystaniem wzorca Proxy .................................................................193 RozwiÈzaniem sÈ poĂrednicy ........................................................................ 194 PoĂrednik ochrony .......................................................................................... 196 PoĂrednicy zdalni ............................................................................................ 197 PoĂrednicy wirtualni jako Ărodek rozleniwiajÈcy ...................................... 198 Eliminacja najbardziej uciÈĝliwych elementów implementacji poĂredników .................................................. 200 Metody i przekazywanie komunikatów ......................................... 201 Metoda method_missing ................................................................... 202 Wysyïanie komunikatów ................................................................... 203 Bezbolesne implementowanie poĂredników ................................. 203 Uĝywanie i naduĝywanie poĂredników ...................................................... 206 Wzorzec Proxy w praktycznych zastosowaniach ...................................... 207 Podsumowanie ................................................................................................ 208 Doskonalenie obiektów za pomocÈ wzorca Decorator ...........................211 Dekoratory: lekarstwo na brzydki kod ........................................................ 212 Dekoracja formalna ......................................................................................... 217 Jak uproĂciÊ model delegacji zadañ ............................................................. 218 Dynamiczna alternatywa dla wzorca projektowego Decorator .............. 219 Opakowywanie metod ....................................................................... 219 Dekorowanie za pomocÈ moduïów ................................................. 220 Uĝywanie i naduĝywanie wzorca projektowego Decorator .................... 221 Dekoratory w praktycznych zastosowaniach ............................................. 222 Podsumowanie ................................................................................................ 223 Jak zyskaÊ pewnoĂÊ, ĝe to ten jedyny, z wykorzystaniem wzorca Singleton ..........................................................225 Jeden obiekt, dostÚp globalny ....................................................................... 225 Zmienne i metody klasowe ........................................................................... 226 Zmienne klasowe ................................................................................ 226 Metody klasowe .................................................................................. 227 Pierwsza próba opracowania singletonu w Ruby ..................................... 228 ZarzÈdzanie jedynym obiektem ....................................................... 229 Upewnianie siÚ, ĝe istnieje tylko jeden ........................................... 230 Moduï Singleton .............................................................................................. 231 Singletony leniwe i chciwe ............................................................................ 232 Konstrukcje alternatywne wzglÚdem klasycznego singletonu ............... 232 Zmienne globalne jako singletony ................................................... 232 Klasy jako singletony .......................................................................... 233 Moduïy jako singletony ..................................................................... 235 SPIS TRE¥CI 111 Pasy bezpieczeñstwa kontra kaftan bezpieczeñstwa ................................ 236 Uĝywanie i naduĝywanie wzorca projektowego Singleton .................... 237 Czy singletony nie sÈ przypadkiem zwykïymi zmiennymi globalnymi? ............................................... 237 WïaĂciwie iloma singletonami dysponujemy? ............................... 238 Singletony i niezbÚdna wiedza ......................................................... 238 Eliminowanie utrudnieñ zwiÈzanych z testowaniem .................. 240 Singletony w praktycznych zastosowaniach .............................................. 241 Podsumowanie ................................................................................................ 242 Rozdziaï 13. Wybór wïaĂciwej klasy za pomocÈ wzorca Factory .................................243 Inny rodzaj kaczego typowania .................................................................... 244 Powrót wzorca projektowego Template Method ...................................... 246 Sparametryzowane metody wytwórcze ...................................................... 248 Klasy to po prostu obiekty ............................................................................. 251 Zïe wieĂci: nasz program podbiï Ăwiat ........................................................ 252 Grupowe tworzenie obiektów ...................................................................... 253 Klasy to po prostu obiekty (raz jeszcze) ...................................................... 255 Korzystanie z nazw ......................................................................................... 257 Uĝywanie i naduĝywanie wzorców fabryk ................................................ 258 Wzorce fabryk w praktycznych zastosowaniach ....................................... 258 Podsumowanie ................................................................................................ 260 Uproszczone konstruowanie obiektów z wykorzystaniem wzorca Builder ..............................................................263 Budowa komputerów ..................................................................................... 264 Klasy budowniczych polimorficznych ........................................................ 267 Klasy budowniczych mogÈ teĝ zapewniÊ Rozdziaï 14. Rozdziaï 15. bezpieczeñstwo tworzenia obiektów ........................................................ 270 Klasy budowniczych wielokrotnego uĝytku .............................................. 270 Lepsza implementacja budowniczych z wykorzystaniem magicznych metod ..................................................... 271 Uĝywanie i naduĝywanie wzorca projektowego Builder ........................ 272 Klasy budowniczych w praktycznych zastosowaniach ............................ 273 Podsumowanie ................................................................................................ 274 ’Èczenie systemu z wykorzystaniem interpretera ...................................275 JÚzyk dostosowany do realizowanego zadania .......................................... 276 Konstruowanie interpretera .......................................................................... 277 Interpreter odnajdywania plików ................................................................ 279 Odnajdywanie wszystkich plików ................................................... 279 Wyszukiwanie plików wedïug nazw .............................................. 280 Wielkie pliki i pliki zapisywalne ....................................................... 281 Bardziej zïoĝone operacje wyszukiwania z uwzglÚdnieniem logicznej negacji, koniunkcji i alternatywy ................................. 282 12 RUBY. WZORCE PROJEKTOWE CZ}¥m III Rozdziaï 16. Rozdziaï 17. Rozdziaï 18. Tworzenie drzewa AST .................................................................................. 284 Prosty analizator skïadniowy ............................................................ 284 Interpreter bez analizatora skïadniowego? ..................................... 286 Analiza skïadniowa danych jÚzyka XML czy YAML? .................. 287 Generowanie zïoĝonych analizatorów skïadniowych za pomocÈ narzÚdzia Racc .............................................................. 288 A moĝe wykorzystaÊ analizator samego jÚzyka Ruby? ................ 288 Uĝywanie i naduĝywanie wzorca projektowego Interpreter .................. 289 Interpretery w praktycznych zastosowaniach ........................................... 290 Podsumowanie ................................................................................................ 291 WZORCE DLA J}ZYKA RUBY ...................................................293 Otwieranie systemów za pomocÈ jÚzyków dziedzinowych (DSL) ......295 JÚzyki dziedzinowe ......................................................................................... 296 JÚzyk DSL kopii zapasowej ............................................................................ 297 Czy to plik z danymi? Nie, to program! ...................................................... 297 Budowa jÚzyka PackRat ................................................................................. 299 ’Èczenie opracowanych dotychczas elementów w jednÈ caïoĂÊ ............ 300 Krytyczne spojrzenie na jÚzyk PackRat ....................................................... 301 Doskonalenie jÚzyka PackRat ....................................................................... 302 Uĝywanie i naduĝywanie wewnÚtrznych jÚzyków DSL ......................... 305 WewnÚtrzne jÚzyki DSL w praktycznych zastosowaniach ..................... 305 Podsumowanie ................................................................................................ 307 Tworzenie niestandardowych obiektów technikÈ metaprogramowania .....................................................................309 Obiekty szyte na miarÚ metoda po metodzie ............................................. 310 Obiekty niestandardowe tworzone moduï po module ............................ 312 Wyczarowywanie zupeïnie nowych metod ............................................... 313 Rzut okiem na wewnÚtrznÈ strukturÚ obiektu ........................................... 317 Uĝywanie i naduĝywanie metaprogramowania ........................................ 318 Metaprogramowanie w praktycznych zastosowaniach ........................... 319 Podsumowanie ................................................................................................ 322 Konwencja ponad konfiguracjÈ ...................................................................323 Interfejs uĝytkownika dobry dla... programistów ..................................... 325 Przewidywanie przyszïych potrzeb ................................................. 326 OszczÚděmy uĝytkownikom powtarzania swojej woli ................ 326 UdostÚpnianie szablonów ................................................................. 327 Bramka wiadomoĂci ........................................................................................ 327 Wybór adaptera ............................................................................................... 329 ’adowanie klas ................................................................................................ 331 Dodanie prostych zabezpieczeñ ................................................................... 333 Uïatwianie uĝytkownikowi wejĂcia w Ăwiat naszego oprogramowania ........................................................................... 335 SPIS TRE¥CI 113 Podsumowanie przykïadu bramki wiadomoĂci ........................................ 336 Uĝywanie i naduĝywanie wzorca projektowego Convention Over Configuration ............................................................... 337 Wzorzec Convention Over Configuration w praktycznych zastosowaniach ............................................................... 338 Podsumowanie ................................................................................................ 339 Konkluzja .........................................................................................................341 DODATKI ................................................................................345 Instalacja jÚzyka Ruby ...................................................................................347 Instalacja Ruby w systemie Microsoft Windows ........................................ 347 Instalacja Ruby w systemie Linux i pozostaïych systemach wywodzÈcych siÚ z systemu UNIX ........................................................... 348 System Mac OS X ............................................................................................ 348 PogïÚbiona analiza .........................................................................................349 Wzorce projektowe ......................................................................................... 349 Ruby .................................................................................................................. 350 Wyraĝenia regularne ...................................................................................... 352 Blogi i witryny internetowe ........................................................................... 352 Skorowidz ........................................................................................................353 Rozdziaï 19. Dodatek A Dodatek B ROZDZIA’ 4. ZastÚpowanie algorytmu strategiÈ W poprzednim rozdziale szukaliĂmy odpowiedzi na pytanie: Jak zróĝnicowaÊ wybranÈ czÚĂÊ algorytmu? Jak sprawiÊ, by trzeci krok procesu piÚciokrokowego raz podejmowaï jedne dziaïania, a innym razem realizowaï nieco inne zadania? W rozdziale 3. przyjÚli- Ămy rozwiÈzanie polegajÈce na stosowaniu wzorca projektowego Template Method, czyli na tworzeniu klasy bazowej z metodÈ szablonowÈ odpowiedzialnÈ za ogólne przetwarzanie podklas charakterystycznych dla mechanizmów szczegóïowych. Gdy- byĂmy raz chcieli realizowaÊ jeden wariant, by innym razem stosowaÊ mechanizm alternatywny, powinniĂmy opracowaÊ dwie podklasy, po jednej dla obu scenariuszy. Wzorzec projektowy Template Method ma, niestety, pewne wady, z których naj- powaĝniejszÈ jest koniecznoĂÊ korzystania z relacji dziedziczenia (wïaĂnie wokóï niej opracowano ten wzorzec). Jak wiemy z rozdziaïu 1., stosowanie Ăcisïej relacji dzie- dziczenia niesie ze sobÈ wiele negatywnych konsekwencji. Niezaleĝnie od wysiïku, jaki wïoĝymy w rozwaĝne projektowanie naszego kodu, podklasy bÚdÈ ĂciĂle zwiÈ- zane ze swojÈ nadklasÈ, co w przypadku tej relacji jest zupeïnie naturalne. Techniki opracowane na podstawie relacji dziedziczenia, w tym wzorzec Template Method, ograniczajÈ wiÚc elastycznoĂÊ naszego kodu. Po wybraniu okreĂlonej wersji algo- rytmu (w naszym przypadku takim krokiem byïo utworzenie obiektu klasy HTML- Report), zmiana tego trybu na inny moĝe siÚ okazaÊ niezwykle trudna. GdybyĂmy zastosowali wzorzec projektowy Template Method i zdecydowali siÚ na zmianÚ formatu raportu, musielibyĂmy utworzyÊ nowy obiekt raportu, np. obiekt klasy PlainTextReport, tylko po to, by uĝyÊ nowego formatu. Mamy inne wyjĂcie? 102 CzÚĂÊ II • WZORCE PROJEKTOWE W J}ZYKU RUBY DELEGUJ, DELEGUJ I JESZCZE RAZ DELEGUJ Alternatywnym rozwiÈzaniem jest uwzglÚdnienie rady sformuïowanej przez BandÚ Czworga i przypomnianÈ w rozdziale 1. tej ksiÈĝki: wybierajmy technikÚ delegowania zadañ. Jaki bÚdzie efekt rezygnacji z kaĝdorazowego tworzenia podklas na rzecz wyodrÚbnienia kïopotliwego, zmienianego kodu do wyspecjalizowanej klasy? BÚdziemy wówczas mogli opracowaÊ caïÈ rodzinÚ klas, po jednej dla kaĝdej odmiany imple- mentowanego mechanizmu. Poniĝej przedstawiono przykïad kodu odpowiedzialnego za formatowanie raportów w jÚzyku HTML przeniesionego na poziom odrÚbnej klasy: class Formatter def output_report( title, text ) raise Wywoïano metodÚ abstrakcyjnÈ end end class HTMLFormatter Formatter def output_report( title, text ) puts( html ) puts( head ) puts( title #{title} /title ) puts( /head ) puts( body ) text.each do |line| puts( p #{line} /p ) end puts( /body ) puts( /html ) end end KlasÚ odpowiedzialnÈ za formatowanie raportu w wersji tekstowej moĝna by zaim- plementowaÊ w nastÚpujÈcy sposób: class PlainTextFormatter Formatter def output_report(title, text) puts( ***** #{title} ***** ) text.each do |line| puts(line) end end end Udaïo nam siÚ przenieĂÊ szczegóïowy kod zwiÈzany z formatowaniem danych wyni- kowych poza klasÚ Report, zatem jej definicja bÚdzie teraz nieporównanie prostsza: class Report attr_reader :title, :text attr_accessor :formatter Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 1103 def initialize(formatter) @title = Raport miesiÚczny @text = [ Wszystko idzie , naprawdÚ dobrze. ] @formatter = formatter end def output_report @formatter.output_report( @title, @text ) end end Okazuje siÚ, ĝe wprowadzona zmiana tylko nieznacznie komplikuje proces korzysta- nia z klasy Report w nowym ksztaïcie. Musimy teraz przekazywaÊ na wejĂciu jej kon- struktora wïaĂciwy obiekt formatujÈcy: report = Report.new(HTMLFormatter.new) report.output_report Banda Czworga okreĂliïa technikÚ „wyodrÚbniania algorytmu do osobnego obiektu” mianem wzorca projektowego Strategy (patrz rysunek 4.1). Wzorzec Strategy opra- cowano w myĂl zaïoĝenia, zgodnie z którym warto definiowaÊ rodzinÚ obiektów, tzw. strategii, realizujÈcych to samo zadanie w róĝny sposób (w naszym przypadku tym zadaniem jest formatowanie raportu). Wszystkie obiekty strategii nie tylko realizujÈ to samo zadanie, ale teĝ obsïugujÈ identyczny interfejs. W prezentowanym przykïadzie ten wspólny interfejs ogranicza siÚ do metody output_report. Skoro wszystkie obiekty strategii z zewnÈtrz wyglÈdajÈ tak samo, uĝytkownik strategii (nazywany przez BandÚ Czworga klasÈ kontekstu — ang. context class) moĝe je traktowaÊ jak wymienne elementy. Oznacza to, ĝe wybór strategii o tyle nie ma wielkiego znaczenia, ĝe wszyst- kie te obiekty wyglÈdajÈ podobnie i realizujÈ tÚ samÈ funkcjÚ. RYSUNEK 4.1. Wzorzec projektowy Strategy Z drugiej strony wybór strategii ma znaczenie ze wzglÚdu na róĝnice w sposobie reali- zacji interesujÈcych nas zadañ. W naszym przykïadzie jedna ze strategii formato- wania generuje raport w jÚzyku HTML, druga generuje raport w formie zwykïego tekstu. GdybyĂmy zastosowali wzorzec Strategy w systemie obliczajÈcym wysokoĂÊ podatku dochodowego, moglibyĂmy uĝyÊ jednej strategii do wyznaczania podatku pïaconego przez etatowego pracownika i innej do obliczania podatku uiszczanego przez pracownika zatrudnionego na podstawie umowy o dzieïo. 104 CzÚĂÊ II • WZORCE PROJEKTOWE W J}ZYKU RUBY Wzorzec projektowy Strategy ma wiele praktycznych zalet. Przykïad raportów po- kazuje, ĝe stosujÈc ten wzorzec, moĝemy zapewniÊ skuteczniejszÈ izolacjÚ naszego kodu dziÚki wyodrÚbnieniu zbioru strategii poza klasÚ gïównÈ. Wzorzec Strategy zwalnia klasÚ Report z jakiejkolwiek odpowiedzialnoĂci czy choÊby koniecznoĂci skïadowania informacji o formacie generowanych raportów. Co wiÚcej, poniewaĝ wzorzec Strategy opiera siÚ na relacji kompozycji i technice de- legacji (zamiast na dziedziczeniu), zmiana strategii w czasie wykonywania programu nie stanowi ĝadnego problemu. Wystarczy wymieniÊ obiekt strategii: report = Report.new(HTMLFormatter.new) report.output_report report.formatter = PlainTextFormatter.new report.output_report Wzorzec projektowy Strategy ma jednÈ cechÚ wspólnÈ ze wzorcem Template Method: oba wzorce umoĝliwiajÈ nam koncentrowanie decyzji o wyborze sposobu realizacji zlecanych zadañ w zaledwie jednym lub dwóch miejscach. W przypadku wzorca Tem- plate Method wïaĂciwÈ odmianÚ algorytmu wybieramy, wskazujÈc konkretnÈ podklasÚ; we wzorcu Strategy taki wybór sprowadza siÚ do wskazania klasy strategii w czasie wykonywania programu. WSPӒDZIELENIE DANYCH PRZEZ KONTEKST I STRATEGI} JednÈ z najwiÚkszych zalet wzorca projektowego Strategy jest izolowanie kodu kon- tekstu i strategii w odrÚbnych klasach, co skutecznie dzieli dane pomiÚdzy dwa nie- zaleĝne byty. Problem w tym, ĝe musimy znaleěÊ jakiĂ sposób pokonania muru dzielÈ- cego oba byty, aby przekazywaÊ informacje, którymi dysponuje kontekst i które sÈ niezbÚdne do prawidïowego funkcjonowania strategii. Ogólnie mówiÈc, mamy do wyboru dwa rozwiÈzania. Po pierwsze, moĝemy konsekwentnie stosowaÊ dotychczasowe rozwiÈzanie polegajÈce na przekazywaniu wszystkich danych niezbÚdnych do pracy obiektów strategii w for- mie argumentów (przekazywanych przez obiekt kontekstu podczas wywoïywania me- tod obiektów strategii). Warto pamiÚtaÊ, ĝe w naszym przykïadzie systemu raportujÈ- cego obiekt raportu byï przekazywany do obiektów formatujÈcych za poĂrednictwem argumentów wywoïañ metody output_report. Przekazywanie kompletnych danych ma tÚ zaletÚ, ĝe pozwala skutecznie izolowaÊ kontekst od obiektów strategii. Strategie majÈ wspólny interfejs; kontekst korzysta tylko z tego interfejsu. Wady opisanej meto- dy sÈ widoczne w sytuacji, gdy musimy przekazywaÊ mnóstwo zïoĝonych danych, co do których nie mamy ĝadnych gwarancji, ĝe rzeczywiĂcie zostanÈ wykorzystane. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 1105 Po drugie, moĝemy przekazywaÊ dane z kontekstu do strategii w formie referencji do samego obiektu kontekstu. Obiekt strategii moĝe wówczas uzyskiwaÊ niezbÚdne dane za poĂrednictwem metod obiektu kontekstu. W naszym przykïadzie systemu rapor- tujÈcego odpowiedni model mógïby mieÊ nastÚpujÈcÈ postaÊ: class Report attr_reader :title, :text attr_accessor :formatter def initialize(formatter) @title = Raport miesiÚczny @text = [ Wszystko idzie , naprawdÚ dobrze. ] @formatter = formatter end def output_report @formatter.output_report(self) end end Obiekt klasy Report przekazuje strategii formatowania referencjÚ do samego siebie; klasa formatujÈca moĝe nastÚpnie uzyskiwaÊ niezbÚdne dane za poĂrednictwem no- wych metod title i text. Poniĝej przedstawiono przebudowanÈ klasÚ HTMLFormatter (przystosowanÈ do korzystania z referencji do obiektu klasy Report): class Formatter def output_report(context) raise Wywoïano metodÚ abstrakcyjnÈ end end class HTMLFormatter Formatter def output_report(context) puts( html ) puts( head ) puts( title #{context.title} /title ) puts( /head ) puts( body ) context.text.each do |line| puts( p #{line} /p ) end puts( /body ) puts( /html ) end end Chociaĝ opisana technika przekazywania kontekstu do strategii skutecznie uprasz- cza przepïyw danych, warto mieÊ na uwadze to, ĝe stosujÈc wskazane rozwiÈzanie, zacieĂniamy zwiÈzki ïÈczÈce kontekst i strategiÚ. W ten sposób istotnie zwiÚkszamy ryzyko wzajemnego uzaleĝnienia klasy kontekstu i klas strategii. 106 CzÚĂÊ II • WZORCE PROJEKTOWE W J}ZYKU RUBY JESZCZE RAZ O KACZYM TYPOWANIU PrzykïadowÈ aplikacjÚ generujÈcÈ raporty, którÈ posïugiwaliĂmy siÚ w tym rozdziale, zbudowano zgodnie z zaleceniami Bandy Czworga odnoĂnie do wzorca projektowego Strategy. Nasza rodzina strategii formatowania skïada siÚ z „abstrakcyjnej” klasy ba- zowej Formatter oraz dwóch podklas: HTMLFormatter i PlainTextFormatter. Pre- zentowany model nie najlepiej pasuje do jÚzyka Ruby, poniewaĝ klasa Formatter w praktyce nie realizuje ĝadnych dziaïañ — istnieje tylko po to, by definiowaÊ wspólny interfejs wszystkich klas formatujÈcych. Wspomniany problem w ĝaden sposób nie wpïywa na formalnÈ poprawnoĂÊ naszego kodu — tak napisany program po prostu dziaïa. Z drugiej strony takie rozwiÈzanie jest sprzeczne z przyjÚtÈ w jÚzyku Ruby filozofiÈ tzw. kaczego typowania. Skoro klasy HTMLFormatter i PlainTextFormatter implementujÈ wspólny interfejs przez zgodne definiowanie metody output_report, wprowadzanie sztucznego tworu (wïaĂnie w formie klasy pozbawionej dziaïañ) po- twierdzajÈcego ten fakt nie ma wiÚkszego sensu. Moĝemy wyeliminowaÊ z naszego projektu klasÚ bazowÈ Formatter za pomocÈ zaledwie kilku uderzeñ w klawisz Delete. Ostatecznie nasz kod bÚdzie miaï nastÚ- pujÈcÈ postaÊ: class Report attr_reader :title, :text attr_accessor :formatter def initialize(formatter) @title = Raport miesiÚczny @text = [ Wszystko idzie , naprawdÚ dobrze. ] @formatter = formatter end def output_report() @formatter.output_report(self) end end class HTMLFormatter def output_report(context) puts( html ) puts( head ) # WyĞwietla pozostaáe dane tego obiektu… puts( title #{context.title} /title ) puts( /head ) puts( body ) context.text.each do |line| puts( p #{line} /p ) end puts( /body ) puts( /html ) end end Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 1107 class PlainTextFormatter def output_report(context) puts( ***** #{context.title} ***** ) context.text.each do |line| puts(line) end end end JeĂli porównamy ten kod z poprzedniÈ wersjÈ, przekonamy siÚ, ĝe rezygnacja z klasy bazowej Formatter nie wymagaïa zbyt wielu dodatkowych zmian. DziÚki dynamicznej kontroli typów nadal moĝemy generowaÊ prawidïowe raporty. Chociaĝ obie wersje dziaïajÈ zgodnie z zaïoĝeniami, do Ăwiata Ruby duĝo lepiej pasuje model pozbawiony klasy bazowej Formatter. OBIEKTY PROC I BLOKI KODU Okazuje siÚ, ĝe eliminacja klasy bazowej nie jest jedynym sposobem dostosowania wzorca projektowego Strategy do charakteru jÚzyka programowania Ruby. Zanim jednak zrobimy kolejny krok, musimy wyjaĂniÊ jeden z najciekawszych aspektów jÚ- zyka Ruby: bloki kodu i obiekty Proc. Jako uĝytkownicy obiektowych jÚzyków programowania spÚdzamy mnóstwo czasu na myĂleniu o obiektach i sposobach ich skutecznego ïÈczenia. Warto jednak zwróciÊ uwagÚ na pewnÈ asymetriÚ wystÚpujÈcÈ w typowym postrzeganiu obiektów. Z reguïy nie mamy problemu z wyodrÚbnianiem danych poza obiekt — moĝemy na przykïad uzyskaÊ wartoĂÊ zmiennej @text obiektu raportu i przekazywaÊ jÈ dalej niezaleĝnie od pozostaïych skïadowych tego obiektu. Z drugiej strony zazwyczaj przyjmujemy, ĝe nasz kod jest ĂciĂle i nierozerwalnie zwiÈzany z poszczególnymi obiektami. Takie przekonanie oczywiĂcie nie znajduje potwierdzenia w praktyce. Co w takim razie powinniĂmy zrobiÊ, aby wyodrÚbniÊ fragmenty kodu poza nasz obiekt i przekazywaÊ je dalej tak jak zwykïe obiekty? Okazuje siÚ, ĝe jÚzyk Ruby oferuje z myĂlÈ o podob- nych operacjach gotowe mechanizmy. W jÚzyku Ruby Proc jest obiektem reprezentujÈcym fragment kodu. Najpopularniej- szym sposobem konstruowania obiektu Proc jest stosowanie metody lambda: hello = lambda do puts( Witaj ) puts( Jestem wewnÈtrz obiektu Proc. ) end W jÚzyku Ruby fragment kodu zawarty pomiÚdzy sïowem kluczowym do a sïowem end okreĂla siÚ mianem bloku kodu1. Metoda lambda zwraca nowy obiekt Proc, czyli 1 Stosuje siÚ teĝ terminy domkniÚcia (ang. closure) oraz lambdy (stÈd nazwa naszej metody tworzÈcej obiekt Proc). 108 CzÚĂÊ II • WZORCE PROJEKTOWE W J}ZYKU RUBY kontener obejmujÈcy caïy kod zdefiniowany pomiÚdzy sïowami do i end. W przed- stawionym przykïadzie obiekt Proc jest wskazywany przez zmiennÈ hello. Kod reprezentowany przez obiekt Proc moĝemy wykonaÊ, wywoïujÈc metodÚ call (trudno sobie wyobraziÊ lepszÈ nazwÚ). JeĂli w przedstawionym przykïadzie wywoïamy metodÚ call obiektu Proc: hello.call otrzymamy komunikaty: Witaj Jestem wewnÈtrz obiektu Proc. WyjÈtkowo cennym aspektem obiektów Proc jest zdolnoĂÊ do funkcjonowania w ota- czajÈcym je Ărodowisku. Oznacza to, ĝe wszelkie zmienne widoczne w momencie tworzenia obiektu Proc pozostajÈ dla tego obiektu dostÚpne takĝe w czasie wykony- wania programu. Na przykïad w poniĝszym fragmencie kodu istnieje tylko jedna zmien- na name: name = Jan proc = Proc.new do name = Maria end proc.call puts(name) Kiedy wykonamy ten kod, zmiennej name w pierwszej kolejnoĂci zostanie przypisany ïañcuch Jan , po czym (po wywoïaniu obiektu Proc) wartoĂÊ tej zmiennej zostanie zastÈpiona przez ïañcuch Maria . Oznacza to, ĝe ostatecznie Ruby wyĂwietli ïañcuch Maria . Z myĂlÈ o programistach, którym konstrukcja do-end wydaje siÚ zbyt rozbudowana, Ruby oferuje krótszÈ skïad- niÚ zïoĝonÈ tylko z nawiasów klamrowych. Poniĝej przedstawiono przykïad uĝycia tej skïadni do utworzenia naszego obiektu Proc: hello = lambda { puts( Witaj, jestem wewnÈtrz obiektu Proc ) } Wielu programistów jÚzyka Ruby przyjÚïo konwencjÚ, zgodnie z którÈ konstrukcjÚ do-end stosuje siÚ do bloków wielowierszowych, a nawiasy klamrowe stosuje siÚ do bloków jednowierszowych2. W tej sytuacji najlepsza wersja prezentowanego przy- kïadu bÚdzie miaïa nastÚpujÈcÈ postaÊ: hello = lambda {puts( Witaj, jestem wewnÈtrz obiektu Proc )} 2 UczciwoĂÊ nakazuje wspomnieÊ o istotnej róĝnicy dzielÈcej obie konstrukcje. W wyraĝeniach jÚzyka Ruby nawiasy klamrowe majÈ wyĝszy priorytet od pary sïów kluczowych do i end. Krótko mówiÈc, nawiasy klamrowe sÈ ĂciĂlej zwiÈzane z wyraĝeniami. Specyfika nawiasów klamrowych jest wi- doczna dopiero wtedy, gdy zrezygnujemy z opcjonalnych nawiasów okrÈgïych. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 1109 Obiekty Proc pod wieloma wzglÚdami przypominajÈ metody. Podobnie jak metody, obiekty Proc nie tylko reprezentujÈ fragmenty kodu, ale teĝ mogÈ zwracaÊ wartoĂci. Obiekt Proc zawsze zwraca ostatniÈ wartoĂÊ wyznaczonÈ w danym bloku — aby zwróciÊ wartoĂÊ z poziomu takiego obiektu, wystarczy siÚ upewniÊ, ĝe jest ona wy- znaczana przez jego ostatnie wyraĝenie. Wszelkie wartoĂci zwracane przez obiekty Proc sÈ przekazywane do kodu wywoïujÈcego za poĂrednictwem metody call. Oznacza to, ĝe kod w postaci: return_24 = lambda {24} puts(return_24.call) wyĂwietli wartoĂÊ: 24 Dla obiektów Proc moĝna teĝ definiowaÊ parametry, choÊ skïadnia tego rodzaju defini- cji jest doĂÊ nietypowa. Zamiast otaczaÊ listÚ parametrów tradycyjnymi nawiasami okrÈgïymi, naleĝy je umieszczaÊ pomiÚdzy dwoma symbolami |: multiply = lambda {|x, y| x * y} Kod w tej formie definiuje obiekt Proc otrzymujÈcy dwa parametry, wyznaczajÈcy ich iloczyn i zwracajÈcy otrzymanÈ wartoĂÊ. Aby wywoïaÊ obiekt Proc z parametrami, wystarczy je przekazaÊ na wejĂciu metody call: n = multiply.call(20, 3) puts(n) n = multiply.call(10, 50) puts(n) Po wykonaniu tego kodu otrzymamy nastÚpujÈce wartoĂci: 60 500 MoĝliwoĂÊ przekazywania bloków kodu jest na tyle przydatna, ĝe twórcy Ruby zde- cydowali siÚ zdefiniowaÊ z myĂlÈ o tej technice specjalnÈ, skróconÈ konstrukcjÚ skïa- dniowÈ. JeĂli chcemy przekazaÊ blok kodu na wejĂciu metody, wystarczy go doïÈczyÊ do jej wywoïania. Tak wywoïana metoda moĝe nastÚpnie wykonaÊ ten blok kodu za pomocÈ sïowa kluczowego yield. Poniĝej zdefiniowano przykïadowÈ metodÚ wyĂwietlajÈcÈ komunikat, wykonujÈcÈ otrzymany blok kodu i wyĂwietlajÈcÈ kolejny komunikat: def run_it puts( Przed wykonaniem yield ) yield puts( Po wykonaniu yield ) end A tak moĝe wyglÈdaÊ wywoïanie metody run_it. Warto pamiÚtaÊ, ĝe w ten sposób dopisujemy blok kodu na koniec wywoïania naszej metody: 110 CzÚĂÊ II • WZORCE PROJEKTOWE W J}ZYKU RUBY run_it do puts( Witaj ) puts( Przybywam do Ciebie z wnÚtrza bloku kodu ) end Kiedy doklejamy blok kodu do wywoïania metody (jak w powyĝszym przykïadzie), wspomniany blok (który w rzeczywistoĂci ma postaÊ obiektu Proc) jest przekazy- wany do tej metody w formie dodatkowego, niewidocznego parametru. Sïowo kluczo- we yield powoduje wiÚc wykonanie tego parametru. W wyniku wykonania powyĝ- szego kodu na ekranie zostanÈ wyĂwietlone nastÚpujÈce komunikaty: Przed wykonaniem yield Witaj Przybywam do Ciebie z wnÚtrza bloku kodu Po wykonaniu yield JeĂli przekazany blok kodu sam otrzymuje jakieĂ parametry, naleĝy je przekazaÊ za poĂrednictwem sïowa kluczowego yield. Oznacza to, ĝe poniĝszy kod: def run_it_with_parameter puts( Przed wykonaniem yield ) yield(24) puts( Po wykonaniu yield ) end run_it_with_parameter do |x| puts( Witaj z wnÚtrza bloku kodu ) puts( Parametr x ma wartoĂÊ #{x} ) end wyĂwietli nastÚpujÈce komunikaty: Przed wykonaniem yield Witaj z wnÚtrza bloku kodu Parametr x ma wartoĂÊ 24 Po wykonaniu yield W niektórych przypadkach warto zdefiniowaÊ wprost parametr reprezentujÈcy blok kodu — w takim przypadku blok przekazany na wejĂciu naszej metody ma postaÊ ar- gumentu przypominajÈcego typowe parametry. W tym celu naleĝy umieĂciÊ specjalny parametr na koñcu listy parametrów tej metody. Tak przekazany parametr (poprze- dzony znakiem ) zostanie przypisany obiektowi Proc utworzonemu na podstawie bloku kodu doïÈczonego do wywoïania danej metody. Oznacza to, ĝe odpowiednikiem przedstawionej powyĝej metody run_it_with_parameters bÚdzie nastÚpujÈca konstrukcja: def run_it_with_parameter( block) puts( Przed wykonaniem yield ) block.call(24) puts( Po wykonaniu yield ) end Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 1111 Symbol moĝna z powodzeniem stosowaÊ takĝe w przeciwnym kierunku. GdybyĂmy umieĂcili obiekt Proc w zmiennej i chcieli go przekazaÊ na wejĂciu metody oczeku- jÈcej bloku kodu, moglibyĂmy przekonwertowaÊ ten obiekt do postaci wymaganego bloku, poprzedzajÈc odpowiedni parametr wïaĂnie znakiem : my_proc = lambda {|x| puts( Parametr x ma wartoĂÊ #{x} )} run_it_with_parameter( my_proc) KRÓTKA ANALIZA KILKU PROSTYCH STRATEGII Co bloki kodu i obiekty Proc majÈ wspólnego ze wzorcem projektowym Strategy? Najkrócej mówiÈc, strategiÚ moĝna postrzegaÊ jako blok wykonywalnego kodu, który „wie”, jak zrealizowaÊ okreĂlone zadanie (np. formatowanie tekstu) i który opakowano w formie obiektu. Przytoczona definicja brzmi znajomo — obiekt Proc bywa okreĂlany wïaĂnie jako fragment kodu opakowany w formie obiektu. WróÊmy teraz do naszego przykïadowego systemu formatujÈcego raporty, gdzie za- stosowanie strategii w formie obiektu Proc okazuje siÚ wyjÈtkowo proste. Zmiany, które musimy wprowadziÊ w kodzie klasy Report, ograniczajÈ siÚ do poprzedzenia parametru przekazywanego na wejĂciu metody initialize symbolem i zmiany nazwy wywoïywanej metody z output_report na call: class Report attr_reader :title, :text attr_accessor :formatter def initialize( formatter) @title = Raport miesiÚczny @text = [ Wszystko idzie , naprawdÚ dobrze. ] @formatter = formatter end def output_report @formatter.call( self ) end end Z nieco innÈ sytuacjÈ mamy jednak do czynienia w przypadku klas odpowiedzial- nych za wïaĂciwe formatowanie. Musimy teraz stworzyÊ obiekty Proc zamiast eg- zemplarzy naszych wyspecjalizowanych klas formatujÈcych: HTML_FORMATTER = lambda do |context| puts( html ) puts( head ) puts( title #{context.title} /title ) puts( /head ) puts( body ) context.text.each do |line| 112 CzÚĂÊ II • WZORCE PROJEKTOWE W J}ZYKU RUBY puts( p #{line} /p ) end puts( /body ) puts Skoro dysponujemy juĝ kodem formatujÈcym w formie obiektu Proc, moĝemy przy- stÈpiÊ do tworzenia raportów. Poniewaĝ dysponujemy obiektem Proc, a konstruktor klasy Report oczekuje bloku kodu, tworzÈc nowy obiekt tej klasy musimy poprze- dziÊ wspomniany obiekt Proc znakiem : report = Report.new HTML_FORMATTER report.output_report Po co w ogóle zajmujemy siÚ problemem implementacji strategii w formie obiektu Proc? Jednym z powodów jest brak koniecznoĂci definiowania specjalnych klas dla poszcze- gólnych strategii — wystarczy opakowaÊ kod w ramach obiektu Proc. Co wiÚcej, sto- sujÈc tÚ technikÚ moĝemy tworzyÊ strategie niemal z niczego, przekazujÈc bloki kodu na wejĂciu istniejÈcej metody. Moĝemy zaimplementowaÊ na przykïad mechanizm formatujÈcy raporty tekstowe w formie nastÚpujÈcego bloku kodu: report = Report.new do |context| puts( ***** #{context.title} ***** ) context.text.each do |line| puts(line) end end Programistom nieprzyzwyczajonym do tego rodzaju konstrukcji bloki kodu mogÈ siÚ wydawaÊ dziwaczne. Z drugiej strony powinniĂmy pamiÚtaÊ, ĝe proponowana technika implementacji wzorca Strategy umoĝliwia zastÈpienie klasÚ kontekstu, klasÚ bazowÈ strategii i wiele konkretnych strategii (wraz ze wszystkimi niezbÚdnymi obiektami) pojedynczÈ klasÈ kontekstu i kilkoma blokami kodu. Czy to oznacza, ĝe powinniĂmy raz na zawsze zapomnieÊ o strategiach implementowa- nych w postaci odrÚbnych klas? Nie do koñca. Strategie w formie bloków kodu zdajÈ egzamin tylko wtedy, gdy ich interfejs jest stosunkowo prosty i obejmuje zaledwie jednÈ metodÚ. Trudno siÚ temu dziwiÊ, skoro call jest jedynÈ metodÈ, którÈ moĝemy wy- woïywaÊ dla obiektów Proc. JeĂli implementowane strategie wymagajÈ interfejsu zïoĝonego z wiÚkszej liczby metod, nie mamy wyboru — musimy skorzystaÊ z tra- dycyjnych klas. JeĂli jednak interfejs strategii jest prosty, koniecznie powinniĂmy rozwaĝyÊ uĝycie bloków kodu. U¿YWANIE I NADU¿YWANIE WZORCA PROJEKTOWEGO STRATEGY NajczÚstszÈ przyczynÈ bïÚdnego implementowania wzorca projektowego Strategy jest niewïaĂciwe definiowanie interfejsu pomiÚdzy kontekstem a strategiami. Musimy pamiÚtaÊ, ĝe naszym celem jest wyodrÚbnienie kompletnego, spójnego i mniej lub Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 1113 bardziej autonomicznego zadania poza obiekt kontekstu i delegowanie go do obiektu strategii. PowinniĂmy zwracaÊ szczególnÈ uwagÚ zarówno na szczegóïy interfejsu ïÈczÈcego kontekst ze strategiÈ, jak i na zwiÈzki wystÚpujÈce pomiÚdzy obiema stro- nami tej relacji. Stosowanie wzorca Strategy bÚdzie bezcelowe, jeĂli zwiÈĝemy kontekst z pierwszÈ strategiÈ na tyle mocno, ĝe uzupeïnienie projektu o drugÈ, trzeciÈ i kolejne strategie okaĝe siÚ niemoĝliwe. WZORZEC STRATEGY W PRAKTYCZNYCH ZASTOSOWANIACH NarzÚdzie rdoc (doïÈczane do dystrybucji jÚzyka Ruby) zawiera wiele mechanizmów opracowanych na podstawie klasycznego, zaproponowanego przez BandÚ Czworga i opartego na klasach wzorca projektowego Strategy. Zadaniem tego narzÚdzia jest generowanie dokumentacji na podstawie kodu ěródïowego. rdoc oferuje moĝliwoĂÊ dokumentowania zarówno programów napisanych w Ruby, jak i programów opra- cowanych w C i (ratunku!) programów stworzonych w jÚzyku FORTRAN. NarzÚdzie rdoc wykorzystuje wzorzec Strategy do obsïugi poszczególnych jÚzyków programo- wania — kaĝdy analizator skïadniowy (wïaĂciwy dla jÚzyków C, Ruby i FORTRAN) ma postaÊ strategii stworzonej z myĂlÈ o innych danych wejĂciowych. NarzÚdzie rdoc oferuje teĝ uĝytkownikowi wybór formatu wyjĂciowego — moĝemy wybraÊ jednÈ z wielu odmian jÚzyka HTML, jÚzyk XML bÈdě jeden z formatów wyko- rzystywanych przez polecenie ri jÚzyka Ruby. Jak nietrudno odgadnÈÊ, kaĝdy z tych formatów wyjĂciowych takĝe jest obsïugiwany przez wyspecjalizowanÈ strategiÚ. Relacje ïÈczÈce poszczególne klasy strategii programu rdoc dobrze ilustrujÈ ogólne podejĂcie do problemu dziedziczenia stosowane w jÚzyku Ruby. ZwiÈzki klas repre- zentujÈcych poszczególne strategie przedstawiono na rysunku 4.2. RYSUNEK 4.2. Klasy generujÈce narzÚdzia rdoc Jak widaÊ na rysunku 4.2, istniejÈ cztery powiÈzane ze sobÈ strategie formatowania danych wyjĂciowych (okreĂlanych w programie rdoc mianem generatorów) i jedna strategia autonomiczna. Wszystkie cztery powiÈzane strategie generujÈ dokumentacjÚ w podobnym formacie — znane wszystkim konstrukcje coĂtam otoczone nawiasami 114 CzÚĂÊ II • WZORCE PROJEKTOWE W J}ZYKU RUBY ostrymi /coĂtam 3. Ostatnia strategia generuje dane wyjĂciowe na potrzeby polecenia ri jÚzyka Ruby, które nie przypominajÈ ani kodu XML-a, ani kodu HTML-a. Jak wynika z diagramu UML przedstawionego na rysunku 4.2, relacje ïÈczÈce poszczególne klasy odzwierciedlajÈ szczegóïy implementacyjne: klasy generujÈce dokumentacjÚ w formatach HTML, CHM i XML z natury rzeczy wspóïdzielÈ znacznÈ czÚĂÊ kodu, stÈd decyzja twórców rdoc o zastosowaniu relacji dziedziczenia. Klasa RIGenerator generuje zupeïnie inne dane wynikowe (w formacie caïkowicie niezwiÈzanym z rodzinÈ jÚzyków XML i HTML). Twórcy rdoc nie zdecydowali siÚ na wspóïdzielenie jednej nadklasy przez wszystkie klasy generatorów tylko dlatego, ĝe wszystkie te klasy im- plementujÈ ten sam interfejs. Ograniczyli siÚ jedynie do zaimplementowania wïa- Ăciwych metod w opisanych klasach. Okazuje siÚ, ĝe z dobrym przykïadem wykorzystania obiektu Proc w roli lekkiej strategii mamy do czynienia na co dzieñ — takie rozwiÈzanie zastosowano w przypadku tablic. JeĂli chcemy posortowaÊ zawartoĂÊ tablicy jÚzyka Ruby, wywoïujemy metodÚ sort: a = [ ryszard , michaï , jan , daniel , robert ] a.sort Metoda sort domyĂlnie sortuje obiekty skïadowane w tabeli, stosujÈc „naturalny” porzÈdek. Co w takim razie powinniĂmy zrobiÊ, jeĂli chcemy uĝyÊ innego schematu porzÈdkowania elementów? Jak naleĝaïoby na przykïad posortowaÊ ïañcuchy wedïug dïugoĂci? Wystarczy przekazaÊ strategiÚ porównywania obiektów w formie bloku kodu: a.sort { |a,b| a.length = b.length } Metoda sort wywoïuje nasz blok kodu za kaĝdym razem, gdy bÚdzie zmuszona po- równaÊ dwa elementy sortowanej tablicy. Nasz blok powinien zwracaÊ wartoĂÊ 1, jeĂli pierwszy element jest wiÚkszy od drugiego; wartoĂÊ 0, jeĂli oba elementy sÈ równe, i wartoĂÊ –1, jeĂli wiÚkszy jest drugi element. Nieprzypadkowo dziaïanie tego kodu przypomina zachowanie operatora = . PODSUMOWANIE Wzorzec projektowy Strategy reprezentuje nieco innÈ, opartÈ na delegowaniu zadañ propozycjÚ rozwiÈzywania tego samego problemu, który jest równieĝ rozwiÈzywany przez wzorzec Template Method. Zamiast upychania zmiennych czÚĂci algorytmu w podklasach, implementujemy kaĝdÈ z wersji tego algorytmu w odrÚbnym obiekcie. Moĝemy nastÚpnie urozmaicaÊ dziaïania tego algorytmu przez wskazywanie obiektowi kontekstu róĝnych obiektów strategii. Oznacza to, ĝe o ile jedna strategia na przykïad generuje raport w formacie HTML, o tyle inna moĝe generowaÊ ten sam raport 3 Format CHM jest odmianÈ HTML-a wykorzystywanÈ do generowania plików pomocy firmy Microsoft. Chciaïbym teĝ podkreĂliÊ, ĝe to kod narzÚdzia rdoc — nie ja — sugeruje, ĝe XML jest odmianÈ jÚ- zyka HTML. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 1115 w formacie PDF; podobnie, jedna strategia moĝe wyznaczaÊ wysokoĂÊ podatku od- prowadzanego przez pracownika etatowego, by inna wyliczaïa podatek naleĝny od pracownika zatrudnionego na podstawie umowy o dzieïo. Mamy do dyspozycji kilka rozwiÈzañ dotyczÈcych przekazywania niezbÚdnych da- nych pomiÚdzy obiektem kontekstu a obiektem strategii. Moĝemy albo przekazywaÊ wszystkie dane w formie parametrów wywoïywanych metod obiektu strategii, albo po prostu przekazywaÊ obiektowi strategii referencjÚ do caïego obiektu kontekstu. Bloki kodu jÚzyka Ruby, które w istocie majÈ postaÊ kodu opakowywanego w ramach tworzonego na bieĝÈco obiektu (a konkretnie obiektu Proc), wprost doskonale na- dajÈ siÚ do bïyskawicznego konstruowania prostych obiektów strategii. Jak siÚ niedïugo przekonamy, wzorzec projektowy Strategy przypomina (przynajm- niej na pierwszy rzut oka) wiele innych wzorców. Wzorzec Strategy wymusza stoso- wanie obiektu (nazywanego kontekstem), który odpowiada za realizacjÚ okreĂlonego zadania. Okazuje siÚ jednak, ĝe wykonanie tego zadania wymaga od kontekstu skorzystania z pomocy innego obiektu (okreĂlanego mianem strategii). Z bardzo podobnym modelem mamy do czynienia w przypadku wzorca projektowego Ob- server (obserwatora), gdzie obiekt realizujÈcy pewne zadania kieruje wywoïania do drugiego obiektu, bez którego jego funkcjonowanie byïoby niemoĝliwe. Okazuje siÚ, ĝe jedynÈ róĝnicÈ dzielÈcÈ oba te wzorce jest intencja programisty. Celem wzorca projektowego Strategy jest dostarczenie obiektowi kontekstu innego obiektu, który „wie”, jak wykonaÊ okreĂlonÈ wersjÚ algorytmu. Zupeïnie inny cel przyĂwieca programiĂcie stosujÈcemu wzorzec Observer — otóĝ stosujemy go wtedy, gdy… Chyba powinniĂmy te rozwaĝania przenieĂÊ do innego rozdziaïu (tak siÚ skïada, ĝe bÚdzie to kolejny rozdziaï).
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Ruby. Wzorce projektowe
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: