SlideShare ist ein Scribd-Unternehmen logo
1 von 23
Downloaden Sie, um offline zu lesen
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œæ swojego kodu dziêki wzorcom projektowym!
                               • Jak rozpocz¹æ przygodê z jêzykiem Ruby?
                               • Jak wykorzystaæ drzemi¹ce w nim mo¿liwoœci?
                               • Jak zwiêkszyæ elastycznoœæ tworzonego kodu za pomoc¹ wzorców projektowych?
                           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.
                               • Podstawy programowania w jêzyku Ruby
                               • Zastosowanie wzorców – takich jak Observer, Composite, Iterator, Command
                                 i wiele innych
Wydawnictwo Helion             • Wykorzystanie technik metaprogramowania do tworzenia obiektów
ul. Koœciuszki 1c                niestandardowych
44-100 Gliwice                 • Wykorzystanie wyra¿eñ regularnych
tel. 032 230 98 63             • U¿ycie jêzyków dziedzinowych
e-mail: helion@helion.pl       • Sposób instalacji jêzyka Ruby
                                         Korzystaj z doœwiadczenia najlepszych programistów – u¿ywaj
                                                     wzorców projektowych w jêzyku Ruby!
S PIS TRE¥CI



                Sïowo wstÚpne .................................................................................................. 15
                Przedmowa ........................................................................................................ 19
                PodziÚkowania .................................................................................................. 25
                O autorze ............................................................................................................ 27

CZ}¥m I         WZORCE PROJEKTOWE I RUBY .................................................29
Rozdziaï 1.     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
Rozdziaï 2.     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

CZ}¥m II      WZORCE PROJEKTOWE W J}ZYKU RUBY ..................................81
Rozdziaï 3.   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
Rozdziaï 4.   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
Rozdziaï 5.   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
SPIS TRE¥CI                 9


              U ywanie i nadu ywanie wzorca projektowego Observer ..................... 127
              Wzorzec Observer w praktycznych zastosowaniach ................................ 129
              Podsumowanie ................................................................................................ 130
Rozdziaï 6.   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
Rozdziaï 7.   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
Rozdziaï 8.   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
Rozdziaï 9.   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.   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
Rozdziaï 11.   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
Rozdziaï 12.   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             11


               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
Rozdziaï 14.   Uproszczone konstruowanie obiektów
               z wykorzystaniem wzorca Builder .............................................................. 263
               Budowa komputerów ..................................................................................... 264
               Klasy budowniczych polimorficznych ........................................................ 267
               Klasy budowniczych mogÈ te zapewniÊ
                 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
Rozdziaï 15.   ’È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


               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

CZ}¥m III      WZORCE DLA J}ZYKA RUBY ...................................................293
Rozdziaï 16.   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
Rozdziaï 17.   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
Rozdziaï 18.   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                13


               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
Rozdziaï 19.   Konkluzja ......................................................................................................... 341

               DODATKI ................................................................................345
Dodatek A      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
Dodatek B      PogïÚbiona analiza ......................................................................................... 349
               Wzorce projektowe ......................................................................................... 349
               Ruby .................................................................................................................. 350
               Wyra enia regularne ...................................................................................... 352
               Blogi i witryny internetowe ........................................................................... 352
               Skorowidz ........................................................................................................ 353
R OZDZIA’ 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            103


           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         105


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              107


             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
                                          1
         end okre la siÚ mianem bloku kodu . 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          109


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        111


  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           113


      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          115


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ï).

Weitere ähnliche Inhalte

Was ist angesagt?

CorelDRAW 11. Ćwiczenia praktyczne
CorelDRAW 11. Ćwiczenia praktyczneCorelDRAW 11. Ćwiczenia praktyczne
CorelDRAW 11. Ćwiczenia praktyczneWydawnictwo Helion
 
Po prostu JavaScript i Ajax. Wydanie VI
Po prostu JavaScript i Ajax. Wydanie VIPo prostu JavaScript i Ajax. Wydanie VI
Po prostu JavaScript i Ajax. Wydanie VIWydawnictwo Helion
 
3ds max 5. Ćwiczenia praktyczne
3ds max 5. Ćwiczenia praktyczne3ds max 5. Ćwiczenia praktyczne
3ds max 5. Ćwiczenia praktyczneWydawnictwo Helion
 
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznikAdobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznikWydawnictwo Helion
 
Photoshop CS/CS PL. 50 praktycznych projektów
Photoshop CS/CS PL. 50 praktycznych projektówPhotoshop CS/CS PL. 50 praktycznych projektów
Photoshop CS/CS PL. 50 praktycznych projektówWydawnictwo Helion
 
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatceFlash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatceWydawnictwo Helion
 
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznikAdobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznikWydawnictwo Helion
 
Photoshop CS2/CS2 PL. Biblia profesjonalisty
Photoshop CS2/CS2 PL. Biblia profesjonalistyPhotoshop CS2/CS2 PL. Biblia profesjonalisty
Photoshop CS2/CS2 PL. Biblia profesjonalistyWydawnictwo Helion
 
Photoshop CS. Ćwiczenia praktyczne
Photoshop CS. Ćwiczenia praktycznePhotoshop CS. Ćwiczenia praktyczne
Photoshop CS. Ćwiczenia praktyczneWydawnictwo Helion
 
Photoshop CS2/CS2 PL. Prosto do celu
Photoshop CS2/CS2 PL. Prosto do celuPhotoshop CS2/CS2 PL. Prosto do celu
Photoshop CS2/CS2 PL. Prosto do celuWydawnictwo Helion
 
Fotografia cyfrowa. Edycja zdjęć. Wydanie II
Fotografia cyfrowa. Edycja zdjęć. Wydanie IIFotografia cyfrowa. Edycja zdjęć. Wydanie II
Fotografia cyfrowa. Edycja zdjęć. Wydanie IIWydawnictwo Helion
 
Adobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. ĆwiczeniaAdobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. ĆwiczeniaWydawnictwo Helion
 

Was ist angesagt? (19)

CorelDRAW 11. Ćwiczenia praktyczne
CorelDRAW 11. Ćwiczenia praktyczneCorelDRAW 11. Ćwiczenia praktyczne
CorelDRAW 11. Ćwiczenia praktyczne
 
Po prostu Flash MX
Po prostu Flash MXPo prostu Flash MX
Po prostu Flash MX
 
Po prostu JavaScript i Ajax. Wydanie VI
Po prostu JavaScript i Ajax. Wydanie VIPo prostu JavaScript i Ajax. Wydanie VI
Po prostu JavaScript i Ajax. Wydanie VI
 
3ds max 5. Ćwiczenia praktyczne
3ds max 5. Ćwiczenia praktyczne3ds max 5. Ćwiczenia praktyczne
3ds max 5. Ćwiczenia praktyczne
 
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznikAdobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
 
JavaScript dla każdego
JavaScript dla każdegoJavaScript dla każdego
JavaScript dla każdego
 
Photoshop CS/CS PL. 50 praktycznych projektów
Photoshop CS/CS PL. 50 praktycznych projektówPhotoshop CS/CS PL. 50 praktycznych projektów
Photoshop CS/CS PL. 50 praktycznych projektów
 
Po prostu Flash MX 2004
Po prostu Flash MX 2004Po prostu Flash MX 2004
Po prostu Flash MX 2004
 
ABC Photoshop CS
ABC Photoshop CSABC Photoshop CS
ABC Photoshop CS
 
ABC Photoshop 7
ABC Photoshop 7ABC Photoshop 7
ABC Photoshop 7
 
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatceFlash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
Flash CS3 Professional PL. Techniki zaawansowane. Klatka po klatce
 
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznikAdobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
 
Photoshop CS2/CS2 PL. Biblia profesjonalisty
Photoshop CS2/CS2 PL. Biblia profesjonalistyPhotoshop CS2/CS2 PL. Biblia profesjonalisty
Photoshop CS2/CS2 PL. Biblia profesjonalisty
 
Photoshop CS. Ćwiczenia praktyczne
Photoshop CS. Ćwiczenia praktycznePhotoshop CS. Ćwiczenia praktyczne
Photoshop CS. Ćwiczenia praktyczne
 
Photoshop CS2/CS2 PL. Prosto do celu
Photoshop CS2/CS2 PL. Prosto do celuPhotoshop CS2/CS2 PL. Prosto do celu
Photoshop CS2/CS2 PL. Prosto do celu
 
Fotografia cyfrowa. Edycja zdjęć. Wydanie II
Fotografia cyfrowa. Edycja zdjęć. Wydanie IIFotografia cyfrowa. Edycja zdjęć. Wydanie II
Fotografia cyfrowa. Edycja zdjęć. Wydanie II
 
SolidWorks 2006 w praktyce
SolidWorks 2006 w praktyceSolidWorks 2006 w praktyce
SolidWorks 2006 w praktyce
 
Adobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. ĆwiczeniaAdobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. Ćwiczenia
 
ABC grafiki komputerowej
ABC grafiki komputerowejABC grafiki komputerowej
ABC grafiki komputerowej
 

Ähnlich wie Ruby. Wzorce projektowe

Programowanie w języku Ruby. Wydanie II
Programowanie w języku Ruby. Wydanie IIProgramowanie w języku Ruby. Wydanie II
Programowanie w języku Ruby. Wydanie IIWydawnictwo Helion
 
Visual Basic .NET. Wzorce projektowe
Visual Basic .NET. Wzorce projektoweVisual Basic .NET. Wzorce projektowe
Visual Basic .NET. Wzorce projektoweWydawnictwo Helion
 
Programowanie w języku C. FAQ
Programowanie w języku C. FAQProgramowanie w języku C. FAQ
Programowanie w języku C. FAQWydawnictwo Helion
 
100 sposobów na Visual Studio
100 sposobów na Visual Studio100 sposobów na Visual Studio
100 sposobów na Visual StudioWydawnictwo Helion
 
Język C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówJęzyk C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówWydawnictwo Helion
 
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktykJęzyk C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktykWydawnictwo Helion
 
Projektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie II
Projektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie IIProjektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie II
Projektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie IIWydawnictwo Helion
 
C++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowaniaC++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowaniaWydawnictwo Helion
 
RailsSpace. Tworzenie społecznościowych serwisów internetowych w Ruby on Rails
RailsSpace. Tworzenie społecznościowych serwisów internetowych w Ruby on RailsRailsSpace. Tworzenie społecznościowych serwisów internetowych w Ruby on Rails
RailsSpace. Tworzenie społecznościowych serwisów internetowych w Ruby on RailsWydawnictwo Helion
 
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązańWyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązańWydawnictwo Helion
 
C++. 50 efektywnych sposobów na udoskonalenie Twoich programów
C++. 50 efektywnych sposobów na udoskonalenie Twoich programówC++. 50 efektywnych sposobów na udoskonalenie Twoich programów
C++. 50 efektywnych sposobów na udoskonalenie Twoich programówWydawnictwo Helion
 
Język C++. Koncepcje i techniki programowania
Język C++. Koncepcje i techniki programowaniaJęzyk C++. Koncepcje i techniki programowania
Język C++. Koncepcje i techniki programowaniaWydawnictwo Helion
 
Projektowanie serwisów WWW. Standardy sieciowe
Projektowanie serwisów WWW. Standardy siecioweProjektowanie serwisów WWW. Standardy sieciowe
Projektowanie serwisów WWW. Standardy siecioweWydawnictwo Helion
 

Ähnlich wie Ruby. Wzorce projektowe (20)

Programowanie w języku Ruby. Wydanie II
Programowanie w języku Ruby. Wydanie IIProgramowanie w języku Ruby. Wydanie II
Programowanie w języku Ruby. Wydanie II
 
Visual Basic .NET. Wzorce projektowe
Visual Basic .NET. Wzorce projektoweVisual Basic .NET. Wzorce projektowe
Visual Basic .NET. Wzorce projektowe
 
C#. Ćwiczenia
C#. ĆwiczeniaC#. Ćwiczenia
C#. Ćwiczenia
 
Programowanie w języku C. FAQ
Programowanie w języku C. FAQProgramowanie w języku C. FAQ
Programowanie w języku C. FAQ
 
100 sposobów na Visual Studio
100 sposobów na Visual Studio100 sposobów na Visual Studio
100 sposobów na Visual Studio
 
Język C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówJęzyk C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistów
 
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktykJęzyk C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
 
Projektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie II
Projektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie IIProjektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie II
Projektowanie zorientowane obiektowo. Wzorce projektowe. Wydanie II
 
Java. Rozmówki
Java. RozmówkiJava. Rozmówki
Java. Rozmówki
 
Uczta programistów
Uczta programistówUczta programistów
Uczta programistów
 
C++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowaniaC++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowania
 
RailsSpace. Tworzenie społecznościowych serwisów internetowych w Ruby on Rails
RailsSpace. Tworzenie społecznościowych serwisów internetowych w Ruby on RailsRailsSpace. Tworzenie społecznościowych serwisów internetowych w Ruby on Rails
RailsSpace. Tworzenie społecznościowych serwisów internetowych w Ruby on Rails
 
C#. Wzorce projektowe
C#. Wzorce projektoweC#. Wzorce projektowe
C#. Wzorce projektowe
 
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązańWyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
 
C++. 50 efektywnych sposobów na udoskonalenie Twoich programów
C++. 50 efektywnych sposobów na udoskonalenie Twoich programówC++. 50 efektywnych sposobów na udoskonalenie Twoich programów
C++. 50 efektywnych sposobów na udoskonalenie Twoich programów
 
Język C++. Koncepcje i techniki programowania
Język C++. Koncepcje i techniki programowaniaJęzyk C++. Koncepcje i techniki programowania
Język C++. Koncepcje i techniki programowania
 
Projektowanie serwisów WWW. Standardy sieciowe
Projektowanie serwisów WWW. Standardy siecioweProjektowanie serwisów WWW. Standardy sieciowe
Projektowanie serwisów WWW. Standardy sieciowe
 
Perl. Ćwiczenia
Perl. ĆwiczeniaPerl. Ćwiczenia
Perl. Ćwiczenia
 
Skrypty powłoki. Od podstaw
Skrypty powłoki. Od podstawSkrypty powłoki. Od podstaw
Skrypty powłoki. Od podstaw
 
Java. Kompendium programisty
Java. Kompendium programistyJava. Kompendium programisty
Java. Kompendium programisty
 

Mehr von Wydawnictwo Helion

Tworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyTworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyWydawnictwo Helion
 
Blog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikBlog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikWydawnictwo Helion
 
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktycznePozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczneWydawnictwo Helion
 
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesieE-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesieWydawnictwo Helion
 
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsMicrosoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsWydawnictwo Helion
 
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie IICo potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie IIWydawnictwo Helion
 
Makrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuMakrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuWydawnictwo Helion
 
Java. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIJava. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIWydawnictwo Helion
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningWydawnictwo Helion
 
PowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykPowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykWydawnictwo Helion
 
Serwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaSerwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaWydawnictwo Helion
 

Mehr von Wydawnictwo Helion (20)

Tworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyTworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. Projekty
 
Blog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikBlog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnik
 
Access w biurze i nie tylko
Access w biurze i nie tylkoAccess w biurze i nie tylko
Access w biurze i nie tylko
 
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktycznePozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
 
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesieE-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
 
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsMicrosoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
 
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie IICo potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
 
Makrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuMakrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółu
 
Windows PowerShell. Podstawy
Windows PowerShell. PodstawyWindows PowerShell. Podstawy
Windows PowerShell. Podstawy
 
Java. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIJava. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie II
 
JavaScript. Pierwsze starcie
JavaScript. Pierwsze starcieJavaScript. Pierwsze starcie
JavaScript. Pierwsze starcie
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny trening
 
PowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykPowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktyk
 
Excel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktykExcel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktyk
 
Access 2007 PL. Seria praktyk
Access 2007 PL. Seria praktykAccess 2007 PL. Seria praktyk
Access 2007 PL. Seria praktyk
 
Word 2007 PL. Seria praktyk
Word 2007 PL. Seria praktykWord 2007 PL. Seria praktyk
Word 2007 PL. Seria praktyk
 
Serwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaSerwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacja
 
AutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PLAutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PL
 
Bazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcieBazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcie
 
Inventor. Pierwsze kroki
Inventor. Pierwsze krokiInventor. Pierwsze kroki
Inventor. Pierwsze kroki
 

Ruby. Wzorce projektowe

  • 1. 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œæ swojego kodu dziêki wzorcom projektowym! • Jak rozpocz¹æ przygodê z jêzykiem Ruby? • Jak wykorzystaæ drzemi¹ce w nim mo¿liwoœci? • Jak zwiêkszyæ elastycznoœæ tworzonego kodu za pomoc¹ wzorców projektowych? 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. • Podstawy programowania w jêzyku Ruby • Zastosowanie wzorców – takich jak Observer, Composite, Iterator, Command i wiele innych Wydawnictwo Helion • Wykorzystanie technik metaprogramowania do tworzenia obiektów ul. Koœciuszki 1c niestandardowych 44-100 Gliwice • Wykorzystanie wyra¿eñ regularnych tel. 032 230 98 63 • U¿ycie jêzyków dziedzinowych e-mail: helion@helion.pl • Sposób instalacji jêzyka Ruby Korzystaj z doœwiadczenia najlepszych programistów – u¿ywaj wzorców projektowych w jêzyku Ruby!
  • 2. S PIS TRE¥CI Sïowo wstÚpne .................................................................................................. 15 Przedmowa ........................................................................................................ 19 PodziÚkowania .................................................................................................. 25 O autorze ............................................................................................................ 27 CZ}¥m I WZORCE PROJEKTOWE I RUBY .................................................29 Rozdziaï 1. 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 Rozdziaï 2. 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
  • 3. 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 CZ}¥m II WZORCE PROJEKTOWE W J}ZYKU RUBY ..................................81 Rozdziaï 3. 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 Rozdziaï 4. 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 Rozdziaï 5. 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
  • 4. SPIS TRE¥CI 9 U ywanie i nadu ywanie wzorca projektowego Observer ..................... 127 Wzorzec Observer w praktycznych zastosowaniach ................................ 129 Podsumowanie ................................................................................................ 130 Rozdziaï 6. 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 Rozdziaï 7. 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 Rozdziaï 8. 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 Rozdziaï 9. 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
  • 5. 10 RUBY. WZORCE PROJEKTOWE Rozdziaï 10. 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 Rozdziaï 11. 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 Rozdziaï 12. 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
  • 6. SPIS TRE¥CI 11 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 Rozdziaï 14. Uproszczone konstruowanie obiektów z wykorzystaniem wzorca Builder .............................................................. 263 Budowa komputerów ..................................................................................... 264 Klasy budowniczych polimorficznych ........................................................ 267 Klasy budowniczych mogÈ te zapewniÊ 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 Rozdziaï 15. ’È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
  • 7. 12 RUBY. WZORCE PROJEKTOWE 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 CZ}¥m III WZORCE DLA J}ZYKA RUBY ...................................................293 Rozdziaï 16. 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 Rozdziaï 17. 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 Rozdziaï 18. 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
  • 8. SPIS TRE¥CI 13 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 Rozdziaï 19. Konkluzja ......................................................................................................... 341 DODATKI ................................................................................345 Dodatek A 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 Dodatek B PogïÚbiona analiza ......................................................................................... 349 Wzorce projektowe ......................................................................................... 349 Ruby .................................................................................................................. 350 Wyra enia regularne ...................................................................................... 352 Blogi i witryny internetowe ........................................................................... 352 Skorowidz ........................................................................................................ 353
  • 9. R OZDZIA’ 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?
  • 10. 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
  • 11. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 103 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.
  • 12. 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.
  • 13. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 105 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.
  • 14. 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
  • 15. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 107 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 1 end okre la siÚ mianem bloku kodu . 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).
  • 16. 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.
  • 17. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 109 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:
  • 18. 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
  • 19. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 111 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|
  • 20. 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
  • 21. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 113 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
  • 22. 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.
  • 23. Rozdziaï 4. • ZAST}POWANIE ALGORYTMU STRATEGIk 115 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ï).