You are on page 1of 23

Ruby.

Wzorce projektowe
Autor: Russ Olsen
Tumaczenie: Mikoaj Szczepaniak
ISBN: 978-83-246-1688-6
Tytu oryginau: Design Patterns in Ruby
(Addison-Wesley Professional Ruby Series)
Format: 172x245, stron: 370

Zwiksz elastyczno swojego kodu dziki wzorcom projektowym!


Jak rozpocz przygod z jzykiem Ruby?
Jak wykorzysta drzemice w nim moliwoci?
Jak zwikszy elastyczno tworzonego kodu za pomoc wzorcw projektowych?

Stworzony w 1995 roku przez Yukihiro Matsumoto jzyk Ruby dziki swym unikalnym
moliwociom zdobywa serca programistw na caym wiecie. Cechy, ktre podbijaj
to nieufne rodowisko, to midzy innymi prosta skadnia z wbudowanymi w ni
wyraeniami regularnymi, automatyczne oczyszczanie pamici i wiele, wiele innych.
Ogromna i chtna do pomocy spoeczno czyni to rozwizanie jeszcze bardziej
atrakcyjnym. Ruby pozwala na korzystanie ze wzorcw projektowych zbioru zasad
i regu prowadzcych do celu w najlepszy, najszybszy i najbardziej elastyczny sposb.
Wzorce projektowe kojarz si gwnie z jzykami Java oraz C i C++. Ksika Ruby.
Wzorce projektowe pokazuje, e mona ich z powodzeniem uywa rwnie w jzyku
Ruby. Dowiesz si z niej, w jaki sposb wykorzysta znane wzorce, takie jak Observer,
Singleton czy te Proxy. Autor przedstawi Ci rwnie nowe wzorce, ktre ze wzgldu
na cechy jzyka Ruby mog zosta w nim zastosowane. Jednak zanim przejdziesz
do ich omawiania, Russ poprowadzi Ci przez podstawy programowania w tym jzyku.
Nauczysz si uywa midzy innymi ptli, instrukcji warunkowych, wyrae regularnych.
Niewtpliwie Twoj ciekawo wzbudzi tak zwany duck typing, ktry oczywicie take
zosta dokadnie tu omwiony. Russ Olsen dziki swojemu wieloletniemu dowiadczeniu
kady wzorzec ilustruje przykadem z ycia wzitym. Uatwi Ci to przyswojenie
i zastosowanie we wasnych projektach przedstawionych tu wzorcw.

Wydawnictwo Helion
ul. Kociuszki 1c
44-100 Gliwice
tel. 032 230 98 63
e-mail: helion@helion.pl

Podstawy programowania w jzyku Ruby


Zastosowanie wzorcw takich jak Observer, Composite, Iterator, Command
i wiele innych
Wykorzystanie technik metaprogramowania do tworzenia obiektw
niestandardowych
Wykorzystanie wyrae regularnych
Uycie jzykw dziedzinowych
Sposb instalacji jzyka Ruby

Korzystaj z dowiadczenia najlepszych programistw uywaj


wzorcw projektowych w jzyku Ruby!

S PIS TRECI

Sowo wstpne .................................................................................................. 15


Przedmowa ........................................................................................................ 19
Podzikowania .................................................................................................. 25
O autorze ............................................................................................................ 27

CZ I

WZORCE PROJEKTOWE I RUBY .................................................29

Rozdzia 1.

Budowa lepszych programw z wykorzystaniem


wzorcw projektowych ................................................................................... 31
Banda Czworga ................................................................................................. 32
Wzorce dla wzorcw ........................................................................................ 33
Oddzielaj elementy zmienne od elementw staych ...................... 33
Programuj pod ktem interfejsu, nie implementacji ....................... 34
Stosuj kompozycj zamiast dziedziczenia ........................................ 36
Deleguj, deleguj i jeszcze raz deleguj ................................................ 40
Czy dane rozwizanie rzeczywicie jest niezbdne ........................ 41
Czternacie z dwudziestu trzech .................................................................... 43
Wzorce projektowe w jzyku Ruby? ............................................................. 45

Rozdzia 2.

Pierwsze kroki w jzyku Ruby ...................................................................... 47


Interaktywny jzyk Ruby ................................................................................ 48
Przywitaj si ze wiatem .................................................................................. 48
Zmienne .............................................................................................................. 51
Typy Fixnum i Bignum .................................................................................... 52
Liczby zmiennoprzecinkowe .......................................................................... 53
W jzyku Ruby nie ma typw prostych ........................................................ 54
Kiedy brakuje obiektw ............................................................................... 55
Prawda, fasz i nil .............................................................................................. 55
Decyzje, decyzje ................................................................................................ 57
Ptle ..................................................................................................................... 58

RUBY. WZORCE PROJEKTOWE

Wicej o a cuchach .......................................................................................... 60


Symbole ............................................................................................................... 63
Tablice ................................................................................................................. 63
Tablice mieszajce ............................................................................................. 65
Wyraenia regularne ........................................................................................ 65
Nasza pierwsza klasa ........................................................................................ 66
Operacje na zmiennych egzemplarzy ........................................................... 68
Obiekt pyta: Kim jestem? ................................................................................. 70
Dziedziczenie, podklasy i nadklasy ............................................................... 71
Opcje argumentw ........................................................................................... 72
Moduy ................................................................................................................ 73
Wyjtki ................................................................................................................ 76
Wtki ................................................................................................................... 77
Zarzdzanie odrbnymi plikami z kodem rdowym .............................. 78
Podsumowanie .................................................................................................. 79

CZ II

WZORCE PROJEKTOWE W JZYKU RUBY ..................................81

Rozdzia 3.

Urozmaicanie algorytmw
za pomoc wzorca projektowego Template Method ................................. 83
Jak stawi czoo typowym problemom .......................................................... 84
Izolowanie elementw zachowujcych dotychczasow form ................ 85
Odkrywanie wzorca projektowego Template Method .............................. 88
Metody zaczepienia .......................................................................................... 89
Gdzie si waciwie podziay wszystkie te deklaracje? ............................... 92
Typy, bezpiecze stwo i elastyczno ............................................................. 93
Testy jednostkowe nie maj charakteru opcjonalnego ............................... 95
Uywanie i naduywanie wzorca projektowego Template Method ....... 97
Szablony w praktycznych zastosowaniach ................................................... 98
Podsumowanie .................................................................................................. 99

Rozdzia 4.

Zastpowanie algorytmu strategi .............................................................. 101


Deleguj, deleguj i jeszcze raz deleguj .......................................................... 102
Wspdzielenie danych przez kontekst i strategi .................................... 104
Jeszcze raz o kaczym typowaniu .................................................................. 106
Obiekty Proc i bloki kodu .............................................................................. 107
Krtka analiza kilku prostych strategii ........................................................ 111
Uywanie i naduywanie wzorca projektowego Strategy ....................... 112
Wzorzec Strategy w praktycznych zastosowaniach .................................. 113
Podsumowanie ................................................................................................ 114

Rozdzia 5.

Jak by na bieco dziki wzorcowi Observer ......................................... 117


Trzymamy rk na pulsie .............................................................................. 117
Jak skuteczniej trzyma rk na pulsie? ...................................................... 119
Wyodrbnianie mechanizmu umoliwiajcego obserwacj .................... 122
Stosowanie blokw kodu w roli obserwatorw ......................................... 125
Odmiany wzorca projektowego Observer .............................................. 126

SPIS TRECI

Uywanie i naduywanie wzorca projektowego Observer ..................... 127


Wzorzec Observer w praktycznych zastosowaniach ................................ 129
Podsumowanie ................................................................................................ 130
Rozdzia 6.

Budowa wikszej cao ci z cz ci za pomoc wzorca Composite ......... 133


Cao i czci ................................................................................................... 134
Tworzenie kompozytw ................................................................................ 136
Doskonalenie implementacji wzorca Composite
z wykorzystaniem operatorw .................................................................. 140
A moe tablica w roli kompozytu? ............................................................... 141
Kopotliwe rnice .......................................................................................... 141
Wskaniki w obie strony ................................................................................ 142
Uywanie i naduywanie wzorca projektowego Composite .................. 143
Kompozyty w praktycznych zastosowaniach ............................................ 145
Podsumowanie ................................................................................................ 147

Rozdzia 7.

Przeszukiwanie kolekcji z wykorzystaniem wzorca Iterator ................ 149


Iteratory zewntrzne ...................................................................................... 149
Iteratory wewntrzne ..................................................................................... 152
Iteratory wewntrzne kontra iteratory wewntrzne ................................ 153
Niezrwnany modu Enumerable ................................................................ 154
Uywanie i naduywanie 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 rozwizanie ...................................................................................... 165
Stosowanie blokw kodu w roli polece ..................................................... 166
Rejestrowanie polece .................................................................................... 167
Wycofywanie operacji za pomoc wzorca Command .............................. 170
Kolejkowanie polece .................................................................................... 173
Uywanie i naduywanie wzorca projektowego Command .................. 174
Wzorzec projektowy Command w praktycznych zastosowaniach ........ 175
Migracje w ramach interfejsu ActiveRecord ................................... 175
Madeleine ............................................................................................. 176
Podsumowanie ................................................................................................ 179

Rozdzia 9.

Wypenianie luk z wykorzystaniem wzorca Adapter ............................. 181


Adaptery programowe ................................................................................... 182
Minimalne niedocignicia ............................................................................ 184
Czy alternatyw moe by adaptowanie istniejcych klas? ..................... 186
Modyfikowanie pojedynczych obiektw .................................................... 187
Adaptowa czy modyfikowa? ..................................................................... 188
Uywanie i naduywanie wzorca projektowego Adapter ....................... 190
Adaptery w praktycznych zastosowaniach ................................................ 190
Podsumowanie ................................................................................................ 191

10

RUBY. WZORCE PROJEKTOWE

Rozdzia 10.

Tworzenie zewntrznego reprezentanta naszego obiektu


z wykorzystaniem wzorca Proxy ................................................................. 193
Rozwizaniem s porednicy ........................................................................ 194
Porednik ochrony .......................................................................................... 196
Porednicy zdalni ............................................................................................ 197
Porednicy wirtualni jako rodek rozleniwiajcy ...................................... 198
Eliminacja najbardziej uciliwych
elementw implementacji porednikw .................................................. 200
Metody i przekazywanie komunikatw ......................................... 201
Metoda method_missing ................................................................... 202
Wysyanie komunikatw ................................................................... 203
Bezbolesne implementowanie porednikw ................................. 203
Uywanie i naduywanie porednikw ...................................................... 206
Wzorzec Proxy w praktycznych zastosowaniach ...................................... 207
Podsumowanie ................................................................................................ 208

Rozdzia 11.

Doskonalenie obiektw za pomoc wzorca Decorator ........................... 211


Dekoratory: lekarstwo na brzydki kod ........................................................ 212
Dekoracja formalna ......................................................................................... 217
Jak uproci model delegacji zada ............................................................. 218
Dynamiczna alternatywa dla wzorca projektowego Decorator .............. 219
Opakowywanie metod ....................................................................... 219
Dekorowanie za pomoc moduw ................................................. 220
Uywanie i naduywanie 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, dostp globalny ....................................................................... 225
Zmienne i metody klasowe ........................................................................... 226
Zmienne klasowe ................................................................................ 226
Metody klasowe .................................................................................. 227
Pierwsza prba opracowania singletonu w Ruby ..................................... 228
Zarzdzanie jedynym obiektem ....................................................... 229
Upewnianie si, e istnieje tylko jeden ........................................... 230
Modu Singleton .............................................................................................. 231
Singletony leniwe i chciwe ............................................................................ 232
Konstrukcje alternatywne wzgldem klasycznego singletonu ............... 232
Zmienne globalne jako singletony ................................................... 232
Klasy jako singletony .......................................................................... 233
Moduy jako singletony ..................................................................... 235

SPIS TRECI

11

Pasy bezpiecze stwa kontra kaftan bezpiecze stwa ................................ 236


Uywanie i naduywanie wzorca projektowego Singleton .................... 237
Czy singletony nie s przypadkiem
zwykymi zmiennymi globalnymi? ............................................... 237
Waciwie iloma singletonami dysponujemy? ............................... 238
Singletony i niezbdna wiedza ......................................................... 238
Eliminowanie utrudnie zwizanych z testowaniem .................. 240
Singletony w praktycznych zastosowaniach .............................................. 241
Podsumowanie ................................................................................................ 242
Rozdzia 13.

Wybr wa ciwej klasy za pomoc wzorca Factory ................................. 243


Inny rodzaj kaczego typowania .................................................................... 244
Powrt wzorca projektowego Template Method ...................................... 246
Sparametryzowane metody wytwrcze ...................................................... 248
Klasy to po prostu obiekty ............................................................................. 251
Ze wieci: nasz program podbi wiat ........................................................ 252
Grupowe tworzenie obiektw ...................................................................... 253
Klasy to po prostu obiekty (raz jeszcze) ...................................................... 255
Korzystanie z nazw ......................................................................................... 257
Uywanie i naduywanie wzorcw fabryk ................................................ 258
Wzorce fabryk w praktycznych zastosowaniach ....................................... 258
Podsumowanie ................................................................................................ 260

Rozdzia 14.

Uproszczone konstruowanie obiektw


z wykorzystaniem wzorca Builder .............................................................. 263
Budowa komputerw ..................................................................................... 264
Klasy budowniczych polimorficznych ........................................................ 267
Klasy budowniczych mog te zapewni
bezpiecze stwo tworzenia obiektw ........................................................ 270
Klasy budowniczych wielokrotnego uytku .............................................. 270
Lepsza implementacja budowniczych
z wykorzystaniem magicznych metod ..................................................... 271
Uywanie i naduywanie wzorca projektowego Builder ........................ 272
Klasy budowniczych w praktycznych zastosowaniach ............................ 273
Podsumowanie ................................................................................................ 274

Rozdzia 15.

czenie systemu z wykorzystaniem interpretera ................................... 275


Jzyk dostosowany do realizowanego zadania .......................................... 276
Konstruowanie interpretera .......................................................................... 277
Interpreter odnajdywania plikw ................................................................ 279
Odnajdywanie wszystkich plikw ................................................... 279
Wyszukiwanie plikw wedug nazw .............................................. 280
Wielkie pliki i pliki zapisywalne ....................................................... 281
Bardziej zoone operacje wyszukiwania z uwzgldnieniem
logicznej negacji, koniunkcji i alternatywy ................................. 282

12

RUBY. WZORCE PROJEKTOWE

Tworzenie drzewa AST .................................................................................. 284


Prosty analizator skadniowy ............................................................ 284
Interpreter bez analizatora skadniowego? ..................................... 286
Analiza skadniowa danych jzyka XML czy YAML? .................. 287
Generowanie zoonych analizatorw skadniowych
za pomoc narzdzia Racc .............................................................. 288
A moe wykorzysta analizator samego jzyka Ruby? ................ 288
Uywanie i naduywanie wzorca projektowego Interpreter .................. 289
Interpretery w praktycznych zastosowaniach ........................................... 290
Podsumowanie ................................................................................................ 291

CZ III

WZORCE DLA JZYKA RUBY ...................................................293

Rozdzia 16.

Otwieranie systemw za pomoc jzykw dziedzinowych (DSL) ...... 295


Jzyki dziedzinowe ......................................................................................... 296
Jzyk DSL kopii zapasowej ............................................................................ 297
Czy to plik z danymi? Nie, to program! ...................................................... 297
Budowa jzyka PackRat ................................................................................. 299

czenie opracowanych dotychczas elementw w jedn cao ............ 300


Krytyczne spojrzenie na jzyk PackRat ....................................................... 301
Doskonalenie jzyka PackRat ....................................................................... 302
Uywanie i naduywanie wewntrznych jzykw DSL ......................... 305
Wewntrzne jzyki DSL w praktycznych zastosowaniach ..................... 305
Podsumowanie ................................................................................................ 307

Rozdzia 17.

Tworzenie niestandardowych obiektw


technik metaprogramowania ..................................................................... 309
Obiekty szyte na miar metoda po metodzie ............................................. 310
Obiekty niestandardowe tworzone modu po module ............................ 312
Wyczarowywanie zupenie nowych metod ............................................... 313
Rzut okiem na wewntrzn struktur obiektu ........................................... 317
Uywanie i naduywanie metaprogramowania ........................................ 318
Metaprogramowanie w praktycznych zastosowaniach ........................... 319
Podsumowanie ................................................................................................ 322

Rozdzia 18.

Konwencja ponad konfiguracj ................................................................... 323


Interfejs uytkownika dobry dla... programistw ..................................... 325
Przewidywanie przyszych potrzeb ................................................. 326
Oszczdmy uytkownikom powtarzania swojej woli ................ 326
Udostpnianie szablonw ................................................................. 327
Bramka wiadomoci ........................................................................................ 327
Wybr adaptera ............................................................................................... 329

adowanie klas ................................................................................................ 331


Dodanie prostych zabezpiecze ................................................................... 333
Uatwianie uytkownikowi wejcia w wiat
naszego oprogramowania ........................................................................... 335

SPIS TRECI

13

Podsumowanie przykadu bramki wiadomoci ........................................ 336


Uywanie i naduywanie wzorca projektowego
Convention Over Configuration ............................................................... 337
Wzorzec Convention Over Configuration
w praktycznych zastosowaniach ............................................................... 338
Podsumowanie ................................................................................................ 339
Rozdzia 19.

Konkluzja ......................................................................................................... 341

Dodatek A

Instalacja jzyka Ruby ................................................................................... 347


Instalacja Ruby w systemie Microsoft Windows ........................................ 347
Instalacja Ruby w systemie Linux i pozostaych systemach
wywodzcych si z systemu UNIX ........................................................... 348
System Mac OS X ............................................................................................ 348

Dodatek B

Pogbiona analiza ......................................................................................... 349


Wzorce projektowe ......................................................................................... 349
Ruby .................................................................................................................. 350
Wyraenia regularne ...................................................................................... 352
Blogi i witryny internetowe ........................................................................... 352

DODATKI ................................................................................345

Skorowidz ........................................................................................................ 353

R OZDZIA 4.

Zastpowanie
algorytmu strategi
W poprzednim rozdziale szukalimy odpowiedzi na pytanie: Jak zrnicowa wybran
cz algorytmu? Jak sprawi, by trzeci krok procesu piciokrokowego raz podejmowa
jedne dziaania, a innym razem realizowa nieco inne zadania? W rozdziale 3. przyjlimy rozwizanie polegajce na stosowaniu wzorca projektowego Template Method,
czyli na tworzeniu klasy bazowej z metod szablonow odpowiedzialn za oglne
przetwarzanie podklas charakterystycznych dla mechanizmw szczegowych. Gdybymy raz chcieli realizowa jeden wariant, by innym razem stosowa mechanizm
alternatywny, powinnimy opracowa dwie podklasy, po jednej dla obu scenariuszy.
Wzorzec projektowy Template Method ma, niestety, pewne wady, z ktrych najpowaniejsz jest konieczno korzystania z relacji dziedziczenia (wanie wok niej
opracowano ten wzorzec). Jak wiemy z rozdziau 1., stosowanie cisej relacji dziedziczenia niesie ze sob wiele negatywnych konsekwencji. Niezalenie od wysiku,
jaki woymy w rozwane projektowanie naszego kodu, podklasy bd cile zwizane ze swoj nadklas, co w przypadku tej relacji jest zupenie naturalne. Techniki
opracowane na podstawie relacji dziedziczenia, w tym wzorzec Template Method,
ograniczaj wic elastyczno naszego kodu. Po wybraniu okrelonej wersji algorytmu (w naszym przypadku takim krokiem byo utworzenie obiektu klasy HTMLReport), zmiana tego trybu na inny moe si okaza niezwykle trudna. Gdybymy
zastosowali wzorzec projektowy Template Method i zdecydowali si na zmian
formatu raportu, musielibymy utworzy nowy obiekt raportu, np. obiekt klasy
PlainTextReport, tylko po to, by uy nowego formatu. Mamy inne wyjcie?

102

Cz II WZORCE PROJEKTOWE W JZYKU RUBY

DELEGUJ, DELEGUJ I JESZCZE RAZ DELEGUJ


Alternatywnym rozwizaniem jest uwzgldnienie rady sformuowanej przez Band
Czworga i przypomnian w rozdziale 1. tej ksiki: wybierajmy technik delegowania
zada . Jaki bdzie efekt rezygnacji z kadorazowego tworzenia podklas na rzecz
wyodrbnienia kopotliwego, zmienianego kodu do wyspecjalizowanej klasy? Bdziemy
wwczas mogli opracowa ca rodzin klas, po jednej dla kadej odmiany implementowanego mechanizmu. Poniej przedstawiono przykad kodu odpowiedzialnego
za formatowanie raportw w jzyku HTML przeniesionego na poziom odrbnej klasy:
class Formatter
def output_report( title, text )
raise 'Wywoano 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 mona by zaimplementowa w nastpujcy sposb:
class PlainTextFormatter < Formatter
def output_report(title, text)
puts("***** #{title} *****")
text.each do |line|
puts(line)
end
end
end

Udao nam si przenie szczegowy kod zwizany z formatowaniem danych wynikowych poza klas Report, zatem jej definicja bdzie teraz nieporwnanie prostsza:
class Report
attr_reader :title, :text
attr_accessor :formatter

Rozdzia 4. ZASTPOWANIE ALGORYTMU STRATEGI

103

def initialize(formatter)
@title = 'Raport miesiczny'
@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 korzystania z klasy Report w nowym ksztacie. Musimy teraz przekazywa na wejciu jej konstruktora waciwy obiekt formatujcy:
report = Report.new(HTMLFormatter.new)
report.output_report

Banda Czworga okrelia technik wyodrbniania algorytmu do osobnego obiektu


mianem wzorca projektowego Strategy (patrz rysunek 4.1). Wzorzec Strategy opracowano w myl zaoenia, zgodnie z ktrym warto definiowa rodzin obiektw, tzw.
strategii, realizujcych to samo zadanie w rny sposb (w naszym przypadku tym
zadaniem jest formatowanie raportu). Wszystkie obiekty strategii nie tylko realizuj to
samo zadanie, ale te obsuguj identyczny interfejs. W prezentowanym przykadzie
ten wsplny interfejs ogranicza si do metody output_report. Skoro wszystkie obiekty
strategii z zewntrz wygldaj tak samo, uytkownik strategii (nazywany przez Band
Czworga klas kontekstu ang. context class) moe je traktowa jak wymienne
elementy. Oznacza to, e wybr strategii o tyle nie ma wielkiego znaczenia, e wszystkie te obiekty wygldaj podobnie i realizuj t sam funkcj.

RYSUNEK 4.1.
Wzorzec projektowy
Strategy

Z drugiej strony wybr strategii ma znaczenie ze wzgldu na rnice w sposobie realizacji interesujcych nas zada . W naszym przykadzie jedna ze strategii formatowania generuje raport w jzyku HTML, druga generuje raport w formie zwykego
tekstu. Gdybymy zastosowali wzorzec Strategy w systemie obliczajcym wysoko
podatku dochodowego, moglibymy uy jednej strategii do wyznaczania podatku
paconego przez etatowego pracownika i innej do obliczania podatku uiszczanego
przez pracownika zatrudnionego na podstawie umowy o dzieo.

104

Cz II WZORCE PROJEKTOWE W JZYKU RUBY

Wzorzec projektowy Strategy ma wiele praktycznych zalet. Przykad raportw pokazuje, e stosujc ten wzorzec, moemy zapewni skuteczniejsz izolacj naszego
kodu dziki wyodrbnieniu zbioru strategii poza klas gwn. Wzorzec Strategy
zwalnia klas Report z jakiejkolwiek odpowiedzialnoci czy choby koniecznoci
skadowania informacji o formacie generowanych raportw.
Co wicej, poniewa wzorzec Strategy opiera si na relacji kompozycji i technice delegacji (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 wspln ze wzorcem Template Method:


oba wzorce umoliwiaj nam koncentrowanie decyzji o wyborze sposobu realizacji
zlecanych zada w zaledwie jednym lub dwch miejscach. W przypadku wzorca Template Method waciw odmian algorytmu wybieramy, wskazujc konkretn podklas;
we wzorcu Strategy taki wybr sprowadza si do wskazania klasy strategii w czasie
wykonywania programu.

WSP DZIELENIE DANYCH


PRZEZ KONTEKST I STRATEGI
Jedn z najwikszych zalet wzorca projektowego Strategy jest izolowanie kodu kontekstu i strategii w odrbnych klasach, co skutecznie dzieli dane pomidzy dwa niezalene byty. Problem w tym, e musimy znale jaki sposb pokonania muru dzielcego oba byty, aby przekazywa informacje, ktrymi dysponuje kontekst i ktre s
niezbdne do prawidowego funkcjonowania strategii. Oglnie mwic, mamy do
wyboru dwa rozwizania.
Po pierwsze, moemy konsekwentnie stosowa dotychczasowe rozwizanie polegajce
na przekazywaniu wszystkich danych niezbdnych do pracy obiektw strategii w formie argumentw (przekazywanych przez obiekt kontekstu podczas wywoywania metod obiektw strategii). Warto pamita, e w naszym przykadzie systemu raportujcego obiekt raportu by przekazywany do obiektw formatujcych za porednictwem
argumentw wywoa metody output_report. Przekazywanie kompletnych danych
ma t zalet, e pozwala skutecznie izolowa kontekst od obiektw strategii. Strategie
maj wsplny interfejs; kontekst korzysta tylko z tego interfejsu. Wady opisanej metody s widoczne w sytuacji, gdy musimy przekazywa mnstwo zoonych danych,
co do ktrych nie mamy adnych gwarancji, e rzeczywicie zostan wykorzystane.

Rozdzia 4. ZASTPOWANIE ALGORYTMU STRATEGI

105

Po drugie, moemy przekazywa dane z kontekstu do strategii w formie referencji do


samego obiektu kontekstu. Obiekt strategii moe wwczas uzyskiwa niezbdne dane
za porednictwem metod obiektu kontekstu. W naszym przykadzie systemu raportujcego odpowiedni model mgby mie nastpujc posta:
class Report
attr_reader :title, :text
attr_accessor :formatter
def initialize(formatter)
@title = 'Raport miesiczny'
@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 formatujca moe nastpnie uzyskiwa niezbdne dane za porednictwem nowych metod title i text. Poniej przedstawiono przebudowan klas HTMLFormatter
(przystosowan do korzystania z referencji do obiektu klasy Report):
class Formatter
def output_report(context)
raise 'Wywoano 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 upraszcza przepyw danych, warto mie na uwadze to, e stosujc wskazane rozwizanie,
zacieniamy zwizki czce kontekst i strategi. W ten sposb istotnie zwikszamy
ryzyko wzajemnego uzalenienia klasy kontekstu i klas strategii.

106

Cz II WZORCE PROJEKTOWE W JZYKU RUBY

JESZCZE RAZ O KACZYM TYPOWANIU


Przykadow aplikacj generujc raporty, ktr posugiwalimy si w tym rozdziale,
zbudowano zgodnie z zaleceniami Bandy Czworga odnonie do wzorca projektowego
Strategy. Nasza rodzina strategii formatowania skada si z abstrakcyjnej klasy bazowej Formatter oraz dwch podklas: HTMLFormatter i PlainTextFormatter. Prezentowany model nie najlepiej pasuje do jzyka Ruby, poniewa klasa Formatter
w praktyce nie realizuje adnych dziaa istnieje tylko po to, by definiowa wsplny
interfejs wszystkich klas formatujcych. Wspomniany problem w aden sposb nie
wpywa na formaln poprawno naszego kodu tak napisany program po prostu
dziaa. Z drugiej strony takie rozwizanie jest sprzeczne z przyjt w jzyku Ruby
filozofi tzw. kaczego typowania. Skoro klasy HTMLFormatter i PlainTextFormatter
implementuj wsplny interfejs przez zgodne definiowanie metody output_report,
wprowadzanie sztucznego tworu (wanie w formie klasy pozbawionej dziaa ) potwierdzajcego ten fakt nie ma wikszego sensu.
Moemy wyeliminowa z naszego projektu klas bazow Formatter za pomoc
zaledwie kilku uderze w klawisz Delete. Ostatecznie nasz kod bdzie mia nastpujc posta:
class Report
attr_reader :title, :text
attr_accessor :formatter
def initialize(formatter)
@title = 'Raport miesiczny'
@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>')
# Wywietla pozostae 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. ZASTPOWANIE ALGORYTMU STRATEGI

107

class PlainTextFormatter
def output_report(context)
puts("***** #{context.title} *****")
context.text.each do |line|
puts(line)
end
end
end

Jeli porwnamy ten kod z poprzedni wersj, przekonamy si, e rezygnacja z klasy
bazowej Formatter nie wymagaa zbyt wielu dodatkowych zmian. Dziki dynamicznej
kontroli typw nadal moemy generowa prawidowe raporty. Chocia obie wersje
dziaaj zgodnie z zaoeniami, do wiata Ruby duo 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 jzyka programowania Ruby. Zanim
jednak zrobimy kolejny krok, musimy wyjani jeden z najciekawszych aspektw jzyka Ruby: bloki kodu i obiekty Proc.
Jako uytkownicy obiektowych jzykw programowania spdzamy mnstwo czasu
na myleniu o obiektach i sposobach ich skutecznego czenia. Warto jednak zwrci
uwag na pewn asymetri wystpujc w typowym postrzeganiu obiektw. Z reguy
nie mamy problemu z wyodrbnianiem danych poza obiekt moemy na przykad
uzyska warto zmiennej @text obiektu raportu i przekazywa j dalej niezalenie
od pozostaych skadowych tego obiektu. Z drugiej strony zazwyczaj przyjmujemy,
e nasz kod jest cile i nierozerwalnie zwizany z poszczeglnymi obiektami. Takie
przekonanie oczywicie nie znajduje potwierdzenia w praktyce. Co w takim razie
powinnimy zrobi, aby wyodrbni fragmenty kodu poza nasz obiekt i przekazywa
je dalej tak jak zwyke obiekty? Okazuje si, e jzyk Ruby oferuje z myl o podobnych operacjach gotowe mechanizmy.
W jzyku Ruby Proc jest obiektem reprezentujcym fragment kodu. Najpopularniejszym sposobem konstruowania obiektu Proc jest stosowanie metody lambda:
hello = lambda do
puts('Witaj')
puts('Jestem wewntrz obiektu Proc.')
end

W jzyku Ruby fragment kodu zawarty pomidzy sowem kluczowym do a sowem


1
end okrela si mianem bloku kodu . Metoda lambda zwraca nowy obiekt Proc, czyli
1

Stosuje si te terminy domknicia (ang. closure) oraz lambdy (std nazwa naszej metody tworzcej
obiekt Proc).

108

Cz II WZORCE PROJEKTOWE W JZYKU RUBY

kontener obejmujcy cay kod zdefiniowany pomidzy sowami do i end. W przedstawionym przykadzie obiekt Proc jest wskazywany przez zmienn hello. Kod
reprezentowany przez obiekt Proc moemy wykona, wywoujc metod call (trudno
sobie wyobrazi lepsz nazw). Jeli w przedstawionym przykadzie wywoamy metod
call obiektu Proc:
hello.call

otrzymamy komunikaty:
Witaj
Jestem wewntrz obiektu Proc.

Wyjtkowo cennym aspektem obiektw Proc jest zdolno do funkcjonowania w otaczajcym je rodowisku. Oznacza to, e wszelkie zmienne widoczne w momencie
tworzenia obiektu Proc pozostaj dla tego obiektu dostpne take w czasie wykonywania programu. Na przykad w poniszym fragmencie kodu istnieje tylko jedna zmienna name:
name = 'Jan'
proc = Proc.new do
name = 'Maria'
end
proc.call
puts(name)

Kiedy wykonamy ten kod, zmiennej name w pierwszej kolejnoci zostanie przypisany
a cuch "Jan", po czym (po wywoaniu obiektu Proc) warto tej zmiennej zostanie
zastpiona przez a cuch "Maria".
Oznacza to, e ostatecznie Ruby wywietli a cuch "Maria". Z myl o programistach,
ktrym konstrukcja do-end wydaje si zbyt rozbudowana, Ruby oferuje krtsz skadni zoon tylko z nawiasw klamrowych. Poniej przedstawiono przykad uycia
tej skadni do utworzenia naszego obiektu Proc:
hello = lambda {
puts('Witaj, jestem wewntrz obiektu Proc')
}

Wielu programistw jzyka Ruby przyjo konwencj, zgodnie z ktr konstrukcj


do-end stosuje si do blokw wielowierszowych, a nawiasy klamrowe stosuje si do
blokw jednowierszowych2. W tej sytuacji najlepsza wersja prezentowanego przykadu bdzie miaa nastpujc posta:
hello = lambda {puts('Witaj, jestem wewntrz obiektu Proc')}
2

Uczciwo nakazuje wspomnie o istotnej rnicy dzielcej obie konstrukcje. W wyraeniach jzyka
Ruby nawiasy klamrowe maj wyszy priorytet od pary sw kluczowych do i end. Krtko mwic,
nawiasy klamrowe s cilej zwizane z wyraeniami. Specyfika nawiasw klamrowych jest widoczna dopiero wtedy, gdy zrezygnujemy z opcjonalnych nawiasw okrgych.

Rozdzia 4. ZASTPOWANIE ALGORYTMU STRATEGI

109

Obiekty Proc pod wieloma wzgldami przypominaj metody. Podobnie jak metody,
obiekty Proc nie tylko reprezentuj fragmenty kodu, ale te mog zwraca wartoci.
Obiekt Proc zawsze zwraca ostatni warto wyznaczon w danym bloku aby
zwrci warto z poziomu takiego obiektu, wystarczy si upewni, e jest ona wyznaczana przez jego ostatnie wyraenie. Wszelkie wartoci zwracane przez obiekty
Proc s przekazywane do kodu wywoujcego za porednictwem metody call.
Oznacza to, e kod w postaci:
return_24 = lambda {24}
puts(return_24.call)

wywietli warto:
24

Dla obiektw Proc mona te definiowa parametry, cho skadnia tego rodzaju definicji jest do nietypowa. Zamiast otacza list parametrw tradycyjnymi nawiasami
okrgymi, naley je umieszcza pomidzy dwoma symbolami |:
multiply = lambda {|x, y| x * y}

Kod w tej formie definiuje obiekt Proc otrzymujcy dwa parametry, wyznaczajcy ich
iloczyn i zwracajcy otrzyman warto. Aby wywoa obiekt Proc z parametrami,
wystarczy je przekaza na wejciu metody call:
n = multiply.call(20, 3)
puts(n)
n = multiply.call(10, 50)
puts(n)

Po wykonaniu tego kodu otrzymamy nastpujce wartoci:


60
500

Moliwo przekazywania blokw kodu jest na tyle przydatna, e twrcy Ruby zdecydowali si zdefiniowa z myl o tej technice specjaln, skrcon konstrukcj skadniow. Jeli chcemy przekaza blok kodu na wejciu metody, wystarczy go doczy
do jej wywoania. Tak wywoana metoda moe nastpnie wykona ten blok kodu
za pomoc sowa kluczowego yield. Poniej zdefiniowano przykadow metod
wywietlajc komunikat, wykonujc otrzymany blok kodu i wywietlajc kolejny
komunikat:
def run_it
puts("Przed wykonaniem yield")
yield
puts("Po wykonaniu yield")
end

A tak moe wyglda wywoanie metody run_it. Warto pamita, e w ten sposb
dopisujemy blok kodu na koniec wywoania naszej metody:

110

Cz II WZORCE PROJEKTOWE W JZYKU RUBY

run_it do
puts('Witaj')
puts('Przybywam do Ciebie z wntrza bloku kodu')
end

Kiedy doklejamy blok kodu do wywoania metody (jak w powyszym przykadzie),


wspomniany blok (ktry w rzeczywistoci ma posta obiektu Proc) jest przekazywany do tej metody w formie dodatkowego, niewidocznego parametru. Sowo kluczowe yield powoduje wic wykonanie tego parametru. W wyniku wykonania powyszego kodu na ekranie zostan wywietlone nastpujce komunikaty:
Przed wykonaniem yield
Witaj
Przybywam do Ciebie z wntrza bloku kodu
Po wykonaniu yield

Jeli przekazany blok kodu sam otrzymuje jakie parametry, naley je przekaza za
porednictwem sowa kluczowego yield. Oznacza to, e poniszy 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 wntrza bloku kodu')
puts("Parametr x ma warto #{x}")
end

wywietli nastpujce komunikaty:


Przed wykonaniem yield
Witaj z wntrza bloku kodu
Parametr x ma warto 24
Po wykonaniu yield

W niektrych przypadkach warto zdefiniowa wprost parametr reprezentujcy blok


kodu w takim przypadku blok przekazany na wejciu naszej metody ma posta argumentu przypominajcego typowe parametry. W tym celu naley umieci specjalny
parametr na ko cu listy parametrw tej metody. Tak przekazany parametr (poprzedzony znakiem &) zostanie przypisany obiektowi Proc utworzonemu na podstawie
bloku kodu doczonego do wywoania danej metody. Oznacza to, e odpowiednikiem
przedstawionej powyej metody run_it_with_parameters bdzie nastpujca
konstrukcja:
def run_it_with_parameter(&block)
puts("Przed wykonaniem yield")
block.call(24)
puts("Po wykonaniu yield")
end

Rozdzia 4. ZASTPOWANIE ALGORYTMU STRATEGI

111

Symbol & mona z powodzeniem stosowa take w przeciwnym kierunku. Gdybymy


umiecili obiekt Proc w zmiennej i chcieli go przekaza na wejciu metody oczekujcej bloku kodu, moglibymy przekonwertowa ten obiekt do postaci wymaganego
bloku, poprzedzajc odpowiedni parametr wanie znakiem &:
my_proc = lambda {|x| puts("Parametr x ma warto #{x}")}
run_it_with_parameter(&my_proc)

KRTKA ANALIZA
KILKU PROSTYCH STRATEGII
Co bloki kodu i obiekty Proc maj wsplnego ze wzorcem projektowym Strategy?
Najkrcej mwic, strategi mona postrzega jako blok wykonywalnego kodu,
ktry wie, jak zrealizowa okrelone zadanie (np. formatowanie tekstu) i ktry
opakowano w formie obiektu. Przytoczona definicja brzmi znajomo obiekt Proc
bywa okrelany wanie jako fragment kodu opakowany w formie obiektu.
Wrmy teraz do naszego przykadowego systemu formatujcego raporty, gdzie zastosowanie strategii w formie obiektu Proc okazuje si wyjtkowo proste. Zmiany,
ktre musimy wprowadzi w kodzie klasy Report, ograniczaj si do poprzedzenia
parametru przekazywanego na wejciu metody initialize symbolem & i zmiany
nazwy wywoywanej metody z output_report na call:
class Report
attr_reader :title, :text
attr_accessor :formatter
def initialize(&formatter)
@title = 'Raport miesiczny'
@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 odpowiedzialnych za waciwe formatowanie. Musimy teraz stworzy obiekty Proc zamiast egzemplarzy naszych wyspecjalizowanych klas formatujcych:
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 JZYKU RUBY

puts(" <p>#{line}</p>" )
end
puts(' </body>')
puts

Skoro dysponujemy ju kodem formatujcym w formie obiektu Proc, moemy przystpi do tworzenia raportw. Poniewa dysponujemy obiektem Proc, a konstruktor
klasy Report oczekuje bloku kodu, tworzc nowy obiekt tej klasy musimy poprzedzi wspomniany obiekt Proc znakiem &:
report = Report.new &HTML_FORMATTER
report.output_report

Po co w ogle zajmujemy si problemem implementacji strategii w formie obiektu Proc?


Jednym z powodw jest brak koniecznoci definiowania specjalnych klas dla poszczeglnych strategii wystarczy opakowa kod w ramach obiektu Proc. Co wicej, stosujc t technik moemy tworzy strategie niemal z niczego, przekazujc bloki kodu
na wejciu istniejcej metody. Moemy zaimplementowa na przykad mechanizm
formatujcy raporty tekstowe w formie nastpujcego 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 powinnimy pamita, e proponowana
technika implementacji wzorca Strategy umoliwia zastpienie klas kontekstu, klas
bazow strategii i wiele konkretnych strategii (wraz ze wszystkimi niezbdnymi
obiektami) pojedyncz klas kontekstu i kilkoma blokami kodu.
Czy to oznacza, e powinnimy raz na zawsze zapomnie o strategiach implementowanych w postaci odrbnych klas? Nie do ko ca. Strategie w formie blokw 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, ktr moemy wywoywa dla obiektw Proc. Jeli implementowane strategie wymagaj interfejsu
zoonego z wikszej liczby metod, nie mamy wyboru musimy skorzysta z tradycyjnych klas. Jeli jednak interfejs strategii jest prosty, koniecznie powinnimy
rozway uycie blokw kodu.

UYWANIE I NADUYWANIE
WZORCA PROJEKTOWEGO STRATEGY
Najczstsz przyczyn bdnego implementowania wzorca projektowego Strategy
jest niewaciwe definiowanie interfejsu pomidzy kontekstem a strategiami. Musimy
pamita, e naszym celem jest wyodrbnienie kompletnego, spjnego i mniej lub

Rozdzia 4. ZASTPOWANIE ALGORYTMU STRATEGI

113

bardziej autonomicznego zadania poza obiekt kontekstu i delegowanie go do obiektu


strategii. Powinnimy zwraca szczegln uwag zarwno na szczegy interfejsu
czcego kontekst ze strategi, jak i na zwizki wystpujce pomidzy obiema stronami tej relacji. Stosowanie wzorca Strategy bdzie bezcelowe, jeli zwiemy kontekst
z pierwsz strategi na tyle mocno, e uzupenienie projektu o drug, trzeci i kolejne
strategie okae si niemoliwe.

WZORZEC STRATEGY
W PRAKTYCZNYCH ZASTOSOWANIACH
Narzdzie rdoc (doczane do dystrybucji jzyka Ruby) zawiera wiele mechanizmw
opracowanych na podstawie klasycznego, zaproponowanego przez Band Czworga
i opartego na klasach wzorca projektowego Strategy. Zadaniem tego narzdzia jest
generowanie dokumentacji na podstawie kodu rdowego. rdoc oferuje moliwo
dokumentowania zarwno programw napisanych w Ruby, jak i programw opracowanych w C i (ratunku!) programw stworzonych w jzyku FORTRAN. Narzdzie
rdoc wykorzystuje wzorzec Strategy do obsugi poszczeglnych jzykw programowania kady analizator skadniowy (waciwy dla jzykw C, Ruby i FORTRAN)
ma posta strategii stworzonej z myl o innych danych wejciowych.
Narzdzie rdoc oferuje te uytkownikowi wybr formatu wyjciowego moemy
wybra jedn z wielu odmian jzyka HTML, jzyk XML bd jeden z formatw wykorzystywanych przez polecenie ri jzyka Ruby. Jak nietrudno odgadn, kady z tych
formatw wyjciowych take jest obsugiwany przez wyspecjalizowan strategi.
Relacje czce poszczeglne klasy strategii programu rdoc dobrze ilustruj oglne
podejcie do problemu dziedziczenia stosowane w jzyku Ruby. Zwizki klas reprezentujcych poszczeglne strategie przedstawiono na rysunku 4.2.

RYSUNEK 4.2.
Klasy generujce
narzdzia rdoc

Jak wida na rysunku 4.2, istniej cztery powizane ze sob strategie formatowania
danych wyjciowych (okrelanych w programie rdoc mianem generatorw) i jedna
strategia autonomiczna. Wszystkie cztery powizane strategie generuj dokumentacj
w podobnym formacie znane wszystkim konstrukcje <cotam> otoczone nawiasami

114

Cz II WZORCE PROJEKTOWE W JZYKU RUBY

ostrymi </cotam>3. Ostatnia strategia generuje dane wyjciowe na potrzeby polecenia


ri jzyka Ruby, ktre nie przypominaj ani kodu XML-a, ani kodu HTML-a. Jak
wynika z diagramu UML przedstawionego na rysunku 4.2, relacje czce poszczeglne
klasy odzwierciedlaj szczegy implementacyjne: klasy generujce dokumentacj
w formatach HTML, CHM i XML z natury rzeczy wspdziel znaczn cz kodu,
std decyzja twrcw rdoc o zastosowaniu relacji dziedziczenia. Klasa RIGenerator
generuje zupenie inne dane wynikowe (w formacie cakowicie niezwizanym z rodzin
jzykw XML i HTML). Twrcy rdoc nie zdecydowali si na wspdzielenie jednej
nadklasy przez wszystkie klasy generatorw tylko dlatego, e wszystkie te klasy implementuj ten sam interfejs. Ograniczyli si jedynie do zaimplementowania waciwych metod w opisanych klasach.
Okazuje si, e z dobrym przykadem wykorzystania obiektu Proc w roli lekkiej strategii
mamy do czynienia na co dzie takie rozwizanie zastosowano w przypadku tablic.
Jeli chcemy posortowa zawarto tablicy jzyka Ruby, wywoujemy metod sort:
a = ['ryszard', 'micha', 'jan', 'daniel', 'robert']
a.sort

Metoda sort domylnie sortuje obiekty skadowane w tabeli, stosujc naturalny


porzdek. Co w takim razie powinnimy zrobi, jeli chcemy uy innego schematu
porzdkowania elementw? Jak naleaoby na przykad posortowa a cuchy wedug
dugoci? Wystarczy przekaza strategi porwnywania obiektw w formie bloku
kodu:
a.sort { |a,b| a.length <=> b.length }

Metoda sort wywouje nasz blok kodu za kadym razem, gdy bdzie zmuszona porwna dwa elementy sortowanej tablicy. Nasz blok powinien zwraca warto 1, jeli
pierwszy element jest wikszy od drugiego; warto 0, jeli oba elementy s rwne,
i warto 1, jeli wikszy jest drugi element. Nieprzypadkowo dziaanie tego kodu
przypomina zachowanie operatora <=>.

PODSUMOWANIE
Wzorzec projektowy Strategy reprezentuje nieco inn, opart na delegowaniu zada
propozycj rozwizywania tego samego problemu, ktry jest rwnie rozwizywany
przez wzorzec Template Method. Zamiast upychania zmiennych czci algorytmu
w podklasach, implementujemy kad z wersji tego algorytmu w odrbnym obiekcie.
Moemy nastpnie urozmaica dziaania tego algorytmu przez wskazywanie obiektowi
kontekstu rnych obiektw strategii. Oznacza to, e o ile jedna strategia na przykad
generuje raport w formacie HTML, o tyle inna moe generowa ten sam raport
3

Format CHM jest odmian HTML-a wykorzystywan do generowania plikw pomocy firmy Microsoft.
Chciabym te podkreli, e to kod narzdzia rdoc nie ja sugeruje, e XML jest odmian jzyka HTML.

Rozdzia 4. ZASTPOWANIE ALGORYTMU STRATEGI

115

w formacie PDF; podobnie, jedna strategia moe wyznacza wysoko podatku odprowadzanego przez pracownika etatowego, by inna wyliczaa podatek naleny od
pracownika zatrudnionego na podstawie umowy o dzieo.
Mamy do dyspozycji kilka rozwiza dotyczcych przekazywania niezbdnych danych pomidzy obiektem kontekstu a obiektem strategii. Moemy albo przekazywa
wszystkie dane w formie parametrw wywoywanych metod obiektu strategii, albo
po prostu przekazywa obiektowi strategii referencj do caego obiektu kontekstu.
Bloki kodu jzyka Ruby, ktre w istocie maj posta kodu opakowywanego w ramach
tworzonego na bieco obiektu (a konkretnie obiektu Proc), wprost doskonale nadaj si do byskawicznego konstruowania prostych obiektw strategii.
Jak si niedugo przekonamy, wzorzec projektowy Strategy przypomina (przynajmniej na pierwszy rzut oka) wiele innych wzorcw. Wzorzec Strategy wymusza stosowanie obiektu (nazywanego kontekstem), ktry odpowiada za realizacj okrelonego
zadania. Okazuje si jednak, e wykonanie tego zadania wymaga od kontekstu
skorzystania z pomocy innego obiektu (okrelanego mianem strategii). Z bardzo
podobnym modelem mamy do czynienia w przypadku wzorca projektowego Observer (obserwatora), gdzie obiekt realizujcy pewne zadania kieruje wywoania do
drugiego obiektu, bez ktrego jego funkcjonowanie byoby niemoliwe.
Okazuje si, e jedyn rnic dzielc oba te wzorce jest intencja programisty. Celem
wzorca projektowego Strategy jest dostarczenie obiektowi kontekstu innego obiektu,
ktry wie, jak wykona okrelon wersj algorytmu. Zupenie inny cel przywieca
programicie stosujcemu wzorzec Observer ot stosujemy go wtedy, gdy
Chyba powinnimy te rozwaania przenie do innego rozdziau (tak si skada, e
bdzie to kolejny rozdzia).

You might also like