Download - Ruby. Wzorce projektowe

Transcript
Page 1: Ruby. Wzorce projektowe

Wydawnictwo Helionul. Ko�ciuszki 1c44-100 Gliwicetel. 032 230 98 63e-mail: [email protected]

Ruby. Wzorce projektoweAutor: Russ OlsenT³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 zasadi 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êduna cechy jêzyka Ruby mog¹ zostaæ w nim zastosowane. Jednak zanim przejdzieszdo 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 przyswojeniei 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 � Wykorzystanie technik metaprogramowania do tworzenia obiektów niestandardowych � Wykorzystanie wyra¿eñ regularnych � U¿ycie jêzyków dziedzinowych � Sposób instalacji jêzyka Ruby

Korzystaj z do�wiadczenia najlepszych programistów � u¿ywajwzorców projektowych w jêzyku Ruby!

Page 2: Ruby. Wzorce projektowe

SPIS TRE�CI

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

CZ��� I WZORCE PROJEKTOWE I RUBY .................................................29Rozdzia� 1. Budowa lepszych programów z wykorzystaniem

wzorców projektowych ................................................................................... 31Banda Czworga ................................................................................................. 32Wzorce dla wzorców ........................................................................................ 33

Oddzielaj elementy zmienne od elementów sta�ych ...................... 33Programuj pod k�tem interfejsu, nie implementacji ....................... 34Stosuj kompozycj� zamiast dziedziczenia ........................................ 36Deleguj, deleguj i jeszcze raz deleguj ................................................ 40Czy dane rozwi�zanie rzeczywi�cie jest niezb�dne ........................ 41

Czterna�cie z dwudziestu trzech .................................................................... 43Wzorce projektowe w j�zyku Ruby? ............................................................. 45

Rozdzia� 2. Pierwsze kroki w j�zyku Ruby ...................................................................... 47Interaktywny j�zyk Ruby ................................................................................ 48Przywitaj si� ze �wiatem .................................................................................. 48Zmienne .............................................................................................................. 51Typy Fixnum i Bignum .................................................................................... 52Liczby zmiennoprzecinkowe .......................................................................... 53W j�zyku Ruby nie ma typów prostych ........................................................ 54Kiedy brakuje obiektów… ............................................................................... 55Prawda, fa�sz i nil .............................................................................................. 55Decyzje, decyzje ................................................................................................ 57P�tle ..................................................................................................................... 58

Page 3: Ruby. Wzorce projektowe

8 RUBY. WZORCE PROJEKTOWE

Wi�cej o �acuchach .......................................................................................... 60Symbole ............................................................................................................... 63Tablice ................................................................................................................. 63Tablice mieszaj�ce ............................................................................................. 65Wyra�enia regularne ........................................................................................ 65Nasza pierwsza klasa ........................................................................................ 66Operacje na zmiennych egzemplarzy ........................................................... 68Obiekt pyta: Kim jestem? ................................................................................. 70Dziedziczenie, podklasy i nadklasy ............................................................... 71Opcje argumentów ........................................................................................... 72Modu�y ................................................................................................................ 73Wyj�tki ................................................................................................................ 76W�tki ................................................................................................................... 77Zarz�dzanie odr�bnymi plikami z kodem �ród�owym .............................. 78Podsumowanie .................................................................................................. 79

CZ��� II WZORCE PROJEKTOWE W J�ZYKU RUBY ..................................81Rozdzia� 3. Urozmaicanie algorytmów

za pomoc� wzorca projektowego Template Method ................................. 83Jak stawi� czo�o typowym problemom .......................................................... 84Izolowanie elementów zachowuj�cych dotychczasow� form� ................ 85Odkrywanie wzorca projektowego Template Method .............................. 88Metody zaczepienia .......................................................................................... 89Gdzie si� w�a�ciwie podzia�y wszystkie te deklaracje? ............................... 92Typy, bezpieczestwo i elastyczno�� ............................................................. 93Testy jednostkowe nie maj� charakteru opcjonalnego ............................... 95U�ywanie i nadu�ywanie wzorca projektowego Template Method ....... 97Szablony w praktycznych zastosowaniach ................................................... 98Podsumowanie .................................................................................................. 99

Rozdzia� 4. Zast�powanie algorytmu strategi� .............................................................. 101Deleguj, deleguj i jeszcze raz deleguj .......................................................... 102Wspó�dzielenie danych przez kontekst i strategi� .................................... 104Jeszcze raz o kaczym typowaniu .................................................................. 106Obiekty Proc i bloki kodu .............................................................................. 107Krótka analiza kilku prostych strategii ........................................................ 111U�ywanie i nadu�ywanie wzorca projektowego Strategy ....................... 112Wzorzec Strategy w praktycznych zastosowaniach .................................. 113Podsumowanie ................................................................................................ 114

Rozdzia� 5. Jak by� na bie��co dzi�ki wzorcowi Observer ......................................... 117Trzymamy r�k� na pulsie .............................................................................. 117Jak skuteczniej trzyma� r�k� na pulsie? ...................................................... 119Wyodr�bnianie mechanizmu umo�liwiaj�cego obserwacj� .................... 122Stosowanie bloków kodu w roli obserwatorów ......................................... 125Odmiany wzorca projektowego Observer .............................................. 126

Page 4: Ruby. Wzorce projektowe

SPIS TRE�CI 99

U�ywanie i nadu�ywanie wzorca projektowego Observer ..................... 127Wzorzec Observer w praktycznych zastosowaniach ................................ 129Podsumowanie ................................................................................................ 130

Rozdzia� 6. Budowa wi�kszej ca�oci z cz�ci za pomoc� wzorca Composite ......... 133Ca�o�� i cz��ci ................................................................................................... 134Tworzenie kompozytów ................................................................................ 136Doskonalenie implementacji wzorca Composite

z wykorzystaniem operatorów .................................................................. 140A mo�e tablica w roli kompozytu? ............................................................... 141K�opotliwe ró�nice .......................................................................................... 141Wska�niki w obie strony ................................................................................ 142U�ywanie i nadu�ywanie wzorca projektowego Composite .................. 143Kompozyty w praktycznych zastosowaniach ............................................ 145Podsumowanie ................................................................................................ 147

Rozdzia� 7. Przeszukiwanie kolekcji z wykorzystaniem wzorca Iterator ................ 149Iteratory zewn�trzne ...................................................................................... 149Iteratory wewn�trzne ..................................................................................... 152Iteratory wewn�trzne kontra iteratory wewn�trzne ................................ 153Niezrównany modu� Enumerable ................................................................ 154U�ywanie i nadu�ywanie wzorca projektowego Iterator ........................ 156Iteratory w praktycznych zastosowaniach ................................................. 158Podsumowanie ................................................................................................ 161

Rozdzia� 8. Doprowadzanie spraw do koca za pomoc� wzorca Command ........... 163Eksplozja podklas ............................................................................................ 164Prostsze rozwi�zanie ...................................................................................... 165Stosowanie bloków kodu w roli polece ..................................................... 166Rejestrowanie polece .................................................................................... 167Wycofywanie operacji za pomoc� wzorca Command .............................. 170Kolejkowanie polece .................................................................................... 173U�ywanie i nadu�ywanie wzorca projektowego Command .................. 174Wzorzec projektowy Command w praktycznych zastosowaniach ........ 175

Migracje w ramach interfejsu ActiveRecord ................................... 175Madeleine ............................................................................................. 176

Podsumowanie ................................................................................................ 179

Rozdzia� 9. Wype�nianie luk z wykorzystaniem wzorca Adapter ............................. 181Adaptery programowe ................................................................................... 182Minimalne niedoci�gni�cia ............................................................................ 184Czy alternatyw� mo�e by� adaptowanie istniej�cych klas? ..................... 186Modyfikowanie pojedynczych obiektów .................................................... 187Adaptowa� czy modyfikowa�? ..................................................................... 188U�ywanie i nadu�ywanie wzorca projektowego Adapter ....................... 190Adaptery w praktycznych zastosowaniach ................................................ 190Podsumowanie ................................................................................................ 191

Page 5: Ruby. Wzorce projektowe

10 RUBY. WZORCE PROJEKTOWE

Rozdzia� 10. Tworzenie zewn�trznego reprezentanta naszego obiektuz wykorzystaniem wzorca Proxy ................................................................. 193Rozwi�zaniem s� po�rednicy ........................................................................ 194Po�rednik ochrony .......................................................................................... 196Po�rednicy zdalni ............................................................................................ 197Po�rednicy wirtualni jako �rodek rozleniwiaj�cy ...................................... 198Eliminacja najbardziej uci��liwych

elementów implementacji po�redników .................................................. 200Metody i przekazywanie komunikatów ......................................... 201Metoda method_missing ................................................................... 202Wysy�anie komunikatów ................................................................... 203Bezbolesne implementowanie po�redników ................................. 203

U�ywanie i nadu�ywanie po�redników ...................................................... 206Wzorzec Proxy w praktycznych zastosowaniach ...................................... 207Podsumowanie ................................................................................................ 208

Rozdzia� 11. Doskonalenie obiektów za pomoc� wzorca Decorator ........................... 211Dekoratory: lekarstwo na brzydki kod ........................................................ 212Dekoracja formalna ......................................................................................... 217Jak upro�ci� model delegacji zada ............................................................. 218Dynamiczna alternatywa dla wzorca projektowego Decorator .............. 219

Opakowywanie metod ....................................................................... 219Dekorowanie za pomoc� modu�ów ................................................. 220

U�ywanie i nadu�ywanie wzorca projektowego Decorator .................... 221Dekoratory w praktycznych zastosowaniach ............................................. 222Podsumowanie ................................................................................................ 223

Rozdzia� 12. Jak zyska� pewno�, �e to ten jedyny,z wykorzystaniem wzorca Singleton .......................................................... 225Jeden obiekt, dost�p globalny ....................................................................... 225Zmienne i metody klasowe ........................................................................... 226

Zmienne klasowe ................................................................................ 226Metody klasowe .................................................................................. 227

Pierwsza próba opracowania singletonu w Ruby ..................................... 228Zarz�dzanie jedynym obiektem ....................................................... 229Upewnianie si�, �e istnieje tylko jeden ........................................... 230

Modu� Singleton .............................................................................................. 231Singletony leniwe i chciwe ............................................................................ 232Konstrukcje alternatywne wzgl�dem klasycznego singletonu ............... 232

Zmienne globalne jako singletony ................................................... 232Klasy jako singletony .......................................................................... 233Modu�y jako singletony ..................................................................... 235

Page 6: Ruby. Wzorce projektowe

SPIS TRE�CI 111

Pasy bezpieczestwa kontra kaftan bezpieczestwa ................................ 236U�ywanie i nadu�ywanie wzorca projektowego Singleton .................... 237

Czy singletony nie s� przypadkiemzwyk�ymi zmiennymi globalnymi? ............................................... 237

W�a�ciwie iloma singletonami dysponujemy? ............................... 238Singletony i niezb�dna wiedza ......................................................... 238Eliminowanie utrudnie zwi�zanych z testowaniem .................. 240

Singletony w praktycznych zastosowaniach .............................................. 241Podsumowanie ................................................................................................ 242

Rozdzia� 13. Wybór w�aciwej klasy za pomoc� wzorca Factory ................................. 243Inny rodzaj kaczego typowania .................................................................... 244Powrót wzorca projektowego Template Method ...................................... 246Sparametryzowane metody wytwórcze ...................................................... 248Klasy to po prostu obiekty ............................................................................. 251Z�e wie�ci: nasz program podbi� �wiat ........................................................ 252Grupowe tworzenie obiektów ...................................................................... 253Klasy to po prostu obiekty (raz jeszcze) ...................................................... 255Korzystanie z nazw ......................................................................................... 257U�ywanie i nadu�ywanie wzorców fabryk ................................................ 258Wzorce fabryk w praktycznych zastosowaniach ....................................... 258Podsumowanie ................................................................................................ 260

Rozdzia� 14. Uproszczone konstruowanie obiektówz wykorzystaniem wzorca Builder .............................................................. 263Budowa komputerów ..................................................................................... 264Klasy budowniczych polimorficznych ........................................................ 267Klasy budowniczych mog� te� zapewni�

bezpieczestwo tworzenia obiektów ........................................................ 270Klasy budowniczych wielokrotnego u�ytku .............................................. 270Lepsza implementacja budowniczych

z wykorzystaniem magicznych metod ..................................................... 271U�ywanie i nadu�ywanie wzorca projektowego Builder ........................ 272Klasy budowniczych w praktycznych zastosowaniach ............................ 273Podsumowanie ................................................................................................ 274

Rozdzia� 15. ��czenie systemu z wykorzystaniem interpretera ................................... 275J�zyk dostosowany do realizowanego zadania .......................................... 276Konstruowanie interpretera .......................................................................... 277Interpreter odnajdywania plików ................................................................ 279

Odnajdywanie wszystkich plików ................................................... 279Wyszukiwanie plików wed�ug nazw .............................................. 280Wielkie pliki i pliki zapisywalne ....................................................... 281Bardziej z�o�one operacje wyszukiwania z uwzgl�dnieniem

logicznej negacji, koniunkcji i alternatywy ................................. 282

Page 7: Ruby. Wzorce projektowe

12 RUBY. WZORCE PROJEKTOWE

Tworzenie drzewa AST .................................................................................. 284Prosty analizator sk�adniowy ............................................................ 284Interpreter bez analizatora sk�adniowego? ..................................... 286Analiza sk�adniowa danych j�zyka XML czy YAML? .................. 287Generowanie z�o�onych analizatorów sk�adniowych

za pomoc� narz�dzia Racc .............................................................. 288A mo�e wykorzysta� analizator samego j�zyka Ruby? ................ 288

U�ywanie i nadu�ywanie wzorca projektowego Interpreter .................. 289Interpretery w praktycznych zastosowaniach ........................................... 290Podsumowanie ................................................................................................ 291

CZ��� III WZORCE DLA J�ZYKA RUBY ...................................................293Rozdzia� 16. Otwieranie systemów za pomoc� j�zyków dziedzinowych (DSL) ...... 295

J�zyki dziedzinowe ......................................................................................... 296J�zyk DSL kopii zapasowej ............................................................................ 297Czy to plik z danymi? Nie, to program! ...................................................... 297Budowa j�zyka PackRat ................................................................................. 299�czenie opracowanych dotychczas elementów w jedn� ca�o�� ............ 300Krytyczne spojrzenie na j�zyk PackRat ....................................................... 301Doskonalenie j�zyka PackRat ....................................................................... 302U�ywanie i nadu�ywanie wewn�trznych j�zyków DSL ......................... 305Wewn�trzne j�zyki DSL w praktycznych zastosowaniach ..................... 305Podsumowanie ................................................................................................ 307

Rozdzia� 17. Tworzenie niestandardowych obiektówtechnik� metaprogramowania ..................................................................... 309Obiekty szyte na miar� metoda po metodzie ............................................. 310Obiekty niestandardowe tworzone modu� po module ............................ 312Wyczarowywanie zupe�nie nowych metod ............................................... 313Rzut okiem na wewn�trzn� struktur� obiektu ........................................... 317U�ywanie i nadu�ywanie metaprogramowania ........................................ 318Metaprogramowanie w praktycznych zastosowaniach ........................... 319Podsumowanie ................................................................................................ 322

Rozdzia� 18. Konwencja ponad konfiguracj� ................................................................... 323Interfejs u�ytkownika dobry dla... programistów ..................................... 325

Przewidywanie przysz�ych potrzeb ................................................. 326Oszcz�d�my u�ytkownikom powtarzania swojej woli ................ 326Udost�pnianie szablonów ................................................................. 327

Bramka wiadomo�ci ........................................................................................ 327Wybór adaptera ............................................................................................... 329adowanie klas ................................................................................................ 331Dodanie prostych zabezpiecze ................................................................... 333U�atwianie u�ytkownikowi wej�cia w �wiat

naszego oprogramowania ........................................................................... 335

Page 8: Ruby. Wzorce projektowe

SPIS TRE�CI 113

Podsumowanie przyk�adu bramki wiadomo�ci ........................................ 336U�ywanie i nadu�ywanie wzorca projektowego

Convention Over Configuration ............................................................... 337Wzorzec Convention Over Configuration

w praktycznych zastosowaniach ............................................................... 338Podsumowanie ................................................................................................ 339

Rozdzia� 19. Konkluzja ......................................................................................................... 341

DODATKI ................................................................................345Dodatek A Instalacja j�zyka Ruby ................................................................................... 347

Instalacja Ruby w systemie Microsoft Windows ........................................ 347Instalacja Ruby w systemie Linux i pozosta�ych systemach

wywodz�cych si� z systemu UNIX ........................................................... 348System Mac OS X ............................................................................................ 348

Dodatek B Pog��biona analiza ......................................................................................... 349Wzorce projektowe ......................................................................................... 349Ruby .................................................................................................................. 350Wyra�enia regularne ...................................................................................... 352Blogi i witryny internetowe ........................................................................... 352

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

Page 9: Ruby. Wzorce projektowe

ROZDZIA� 4.

Zast�powaniealgorytmu 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ólneprzetwarzanie podklas charakterystycznych dla mechanizmów szczegó�owych. Gdy-by�my raz chcieli realizowa� jeden wariant, by innym razem stosowa� mechanizmalternatywny, 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ó� niejopracowano 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. Technikiopracowane 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�myzastosowali wzorzec projektowy Template Method i zdecydowali si� na zmian�formatu raportu, musieliby�my utworzy� nowy obiekt raportu, np. obiekt klasyPlainTextReport, tylko po to, by u�y� nowego formatu. Mamy inne wyj�cie?

Page 10: Ruby. Wzorce projektowe

102 Cz��� II • WZORCE PROJEKTOWE W J�ZYKU RUBY

DELEGUJ, DELEGUJ I JESZCZE RAZ DELEGUJAlternatywnym rozwi�zaniem jest uwzgl�dnienie rady sformu�owanej przez Band�Czworga i przypomnian� w rozdziale 1. tej ksi��ki: wybierajmy technik� delegowaniazada. Jaki b�dzie efekt rezygnacji z ka�dorazowego tworzenia podklas na rzeczwyodr�bnienia k�opotliwego, zmienianego kodu do wyspecjalizowanej klasy? B�dziemywówczas mogli opracowa� ca�� rodzin� klas, po jednej dla ka�dej odmiany imple-mentowanego mechanizmu. Poni�ej przedstawiono przyk�ad kodu odpowiedzialnegoza 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�' endend

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>') endend

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 endend

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

Page 11: Ruby. Wzorce projektowe

Rozdzia� 4. • ZAST�POWANIE ALGORYTMU STRATEGI 1103

def initialize(formatter) @title = 'Raport miesi�czny' @text = [ 'Wszystko idzie', 'naprawd� dobrze.' ] @formatter = formatter end

def output_report @formatter.output_report( @title, @text ) endend

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 tymzadaniem jest formatowanie raportu). Wszystkie obiekty strategii nie tylko realizuj� tosamo zadanie, ale te� obs�uguj� identyczny interfejs. W prezentowanym przyk�adzieten wspólny interfejs ogranicza si� do metody output_report. Skoro wszystkie obiektystrategii z zewn�trz wygl�daj� tak samo, u�ytkownik strategii (nazywany przez Band�Czworga klas� kontekstu — ang. context class) mo�e je traktowa� jak wymienneelementy. 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 projektowyStrategy

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�egotekstu. Gdyby�my zastosowali wzorzec Strategy w systemie obliczaj�cym wysoko��podatku dochodowego, mogliby�my u�y� jednej strategii do wyznaczania podatkup�aconego przez etatowego pracownika i innej do obliczania podatku uiszczanegoprzez pracownika zatrudnionego na podstawie umowy o dzie�o.

Page 12: Ruby. Wzorce projektowe

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� naszegokodu dzi�ki wyodr�bnieniu zbioru strategii poza klas� g�ówn�. Wzorzec Strategyzwalnia klas� Report z jakiejkolwiek odpowiedzialno�ci czy cho�by konieczno�cisk�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 programunie stanowi �adnego problemu. Wystarczy wymieni� obiekt strategii:

report = Report.new(HTMLFormatter.new)report.output_report

report.formatter = PlainTextFormatter.newreport.output_report

Wzorzec projektowy Strategy ma jedn� cech� wspóln� ze wzorcem Template Method:oba wzorce umo�liwiaj� nam koncentrowanie decyzji o wyborze sposobu realizacjizlecanych 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 czasiewykonywania programu.

WSPÓ�DZIELENIE DANYCHPRZEZ 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 dowyboru dwa rozwi�zania.

Po pierwsze, mo�emy konsekwentnie stosowa� dotychczasowe rozwi�zanie polegaj�cena 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�rednictwemargumentów wywo�a metody output_report. Przekazywanie kompletnych danychma t� zalet�, �e pozwala skutecznie izolowa� kontekst od obiektów strategii. Strategiemaj� 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.

Page 13: Ruby. Wzorce projektowe

Rozdzia� 4. • ZAST�POWANIE ALGORYTMU STRATEGI 1105

Po drugie, mo�emy przekazywa� dane z kontekstu do strategii w formie referencji dosamego obiektu kontekstu. Obiekt strategii mo�e wówczas uzyskiwa� niezb�dne daneza 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) endend

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�' endend

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>') endend

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�kszamyryzyko wzajemnego uzale�nienia klasy kontekstu i klas strategii.

Page 14: Ruby. Wzorce projektowe

106 Cz��� II • WZORCE PROJEKTOWE W J�ZYKU RUBY

JESZCZE RAZ O KACZYM TYPOWANIUPrzyk�adow� aplikacj� generuj�c� raporty, któr� pos�ugiwali�my si� w tym rozdziale,zbudowano zgodnie z zaleceniami Bandy Czworga odno�nie do wzorca projektowegoStrategy. 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 Formatterw praktyce nie realizuje �adnych dzia�a — istnieje tylko po to, by definiowa� wspólnyinterfejs wszystkich klas formatuj�cych. Wspomniany problem w �aden sposób niewp�ywa na formaln� poprawno�� naszego kodu — tak napisany program po prostudzia�a. Z drugiej strony takie rozwi�zanie jest sprzeczne z przyj�t� w j�zyku Rubyfilozofi� tzw. kaczego typowania. Skoro klasy HTMLFormatter i PlainTextFormatterimplementuj� 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) endend

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>') endend

Page 15: Ruby. Wzorce projektowe

Rozdzia� 4. • ZAST�POWANIE ALGORYTMU STRATEGI 1107

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

Je�li porównamy ten kod z poprzedni� wersj�, przekonamy si�, �e rezygnacja z klasybazowej Formatter nie wymaga�a zbyt wielu dodatkowych zmian. Dzi�ki dynamicznejkontroli typów nadal mo�emy generowa� prawid�owe raporty. Chocia� obie wersjedzia�aj� zgodnie z za�o�eniami, do �wiata Ruby du�o lepiej pasuje model pozbawionyklasy bazowej Formatter.

OBIEKTY PROC I BLOKI KODUOkazuje si�, �e eliminacja klasy bazowej nie jest jedynym sposobem dostosowaniawzorca projektowego Strategy do charakteru j�zyka programowania Ruby. Zanimjednak 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 czasuna 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�ynie mamy problemu z wyodr�bnianiem danych poza obiekt — mo�emy na przyk�aduzyska� warto�� zmiennej @text obiektu raportu i przekazywa� j� dalej niezale�nieod 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. Takieprzekonanie oczywi�cie nie znajduje potwierdzenia w praktyce. Co w takim raziepowinni�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�owemend okre�la si� mianem bloku kodu1. Metoda lambda zwraca nowy obiekt Proc, czyli

1 Stosuje si� te� terminy domkni�cia (ang. closure) oraz lambdy (st�d nazwa naszej metody tworz�cej

obiekt Proc).

Page 16: Ruby. Wzorce projektowe

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. Kodreprezentowany przez obiekt Proc mo�emy wykona�, wywo�uj�c metod� call (trudnosobie wyobrazi� lepsz� nazw�). Je�li w przedstawionym przyk�adzie wywo�amy metod�call obiektu Proc:

hello.call

otrzymamy komunikaty:

WitajJestem 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 momencietworzenia 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.callputs(name)

Kiedy wykonamy ten kod, zmiennej name w pierwszej kolejno�ci zostanie przypisany�acuch "Jan", po czym (po wywo�aniu obiektu Proc) warto�� tej zmiennej zostaniezast�piona przez �acuch "Maria".

Oznacza to, �e ostatecznie Ruby wy�wietli �acuch "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�yciatej 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� doblokó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.

Page 17: Ruby. Wzorce projektowe

Rozdzia� 4. • ZAST�POWANIE ALGORYTMU STRATEGI 1109

Obiekty Proc pod wieloma wzgl�dami przypominaj� metody. Podobnie jak metody,obiekty Proc nie tylko reprezentuj� fragmenty kodu, ale te� mog� zwraca� warto�ci.Obiekt Proc zawsze zwraca ostatni� warto�� wyznaczon� w danym bloku — abyzwróci� warto�� z poziomu takiego obiektu, wystarczy si� upewni�, �e jest ona wy-znaczana przez jego ostatnie wyra�enie. Wszelkie warto�ci zwracane przez obiektyProc 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 nawiasamiokr�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 ichiloczyn 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:

60500

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 koduza pomoc� s�owa kluczowego yield. Poni�ej zdefiniowano przyk�adow� metod�wy�wietlaj�c� komunikat, wykonuj�c� otrzymany blok kodu i wy�wietlaj�c� kolejnykomunikat:

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óbdopisujemy blok kodu na koniec wywo�ania naszej metody:

Page 18: Ruby. Wzorce projektowe

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 yieldWitajPrzybywam do Ciebie z wn�trza bloku koduPo wykonaniu yield

Je�li przekazany blok kodu sam otrzymuje jakie� parametry, nale�y je przekaza� zapo�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 yieldWitaj z wn�trza bloku koduParametr x ma warto�� 24Po wykonaniu yield

W niektórych przypadkach warto zdefiniowa� wprost parametr reprezentuj�cy blokkodu — 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� specjalnyparametr na kocu listy parametrów tej metody. Tak przekazany parametr (poprze-dzony znakiem &) zostanie przypisany obiektowi Proc utworzonemu na podstawiebloku kodu do��czonego do wywo�ania danej metody. Oznacza to, �e odpowiednikiemprzedstawionej powy�ej metody run_it_with_parameters b�dzie nast�puj�cakonstrukcja:

def run_it_with_parameter(&block) puts("Przed wykonaniem yield") block.call(24) puts("Po wykonaniu yield")end

Page 19: Ruby. Wzorce projektowe

Rozdzia� 4. • ZAST�POWANIE ALGORYTMU STRATEGI 1111

Symbol & mo�na z powodzeniem stosowa� tak�e w przeciwnym kierunku. Gdyby�myumie�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 wymaganegobloku, 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 ANALIZAKILKU 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óryopakowano w formie obiektu. Przytoczona definicja brzmi znajomo — obiekt Procbywa 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 poprzedzeniaparametru przekazywanego na wej�ciu metody initialize symbolem & i zmianynazwy 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 ) endend

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|

Page 20: Ruby. Wzorce projektowe

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 konstruktorklasy Report oczekuje bloku kodu, tworz�c nowy obiekt tej klasy musimy poprze-dzi� wspomniany obiekt Proc znakiem &:

report = Report.new &HTML_FORMATTERreport.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 koduna wej�ciu istniej�cej metody. Mo�emy zaimplementowa� na przyk�ad mechanizmformatuj�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) endend

Programistom nieprzyzwyczajonym do tego rodzaju konstrukcji bloki kodu mog�si� wydawa� dziwaczne. Z drugiej strony powinni�my pami�ta�, �e proponowanatechnika implementacji wzorca Strategy umo�liwia zast�pienie klas� kontekstu, klas�bazow� strategii i wiele konkretnych strategii (wraz ze wszystkimi niezb�dnymiobiektami) 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 koca. 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� interfejsuz�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�myrozwa�y� u�ycie bloków kodu.

U�YWANIE I NADU�YWANIEWZORCA PROJEKTOWEGO STRATEGY

Najcz�stsz� przyczyn� b��dnego implementowania wzorca projektowego Strategyjest niew�a�ciwe definiowanie interfejsu pomi�dzy kontekstem a strategiami. Musimypami�ta�, �e naszym celem jest wyodr�bnienie kompletnego, spójnego i mniej lub

Page 21: Ruby. Wzorce projektowe

Rozdzia� 4. • ZAST�POWANIE ALGORYTMU STRATEGI 1113

bardziej autonomicznego zadania poza obiekt kontekstu i delegowanie go do obiektustrategii. 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 kontekstz pierwsz� strategi� na tyle mocno, �e uzupe�nienie projektu o drug�, trzeci� i kolejnestrategie oka�e si� niemo�liwe.

WZORZEC STRATEGYW PRAKTYCZNYCH ZASTOSOWANIACH

Narz�dzie rdoc (do��czane do dystrybucji j�zyka Ruby) zawiera wiele mechanizmówopracowanych na podstawie klasycznego, zaproponowanego przez Band� Czworgai opartego na klasach wzorca projektowego Strategy. Zadaniem tego narz�dzia jestgenerowanie 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�dzierdoc 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�emywybra� 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 tychformatów wyj�ciowych tak�e jest obs�ugiwany przez wyspecjalizowan� strategi�.Relacje ��cz�ce poszczególne klasy strategii programu rdoc dobrze ilustruj� ogólnepodej�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�cenarz�dzia rdoc

Jak wida� na rysunku 4.2, istniej� cztery powi�zane ze sob� strategie formatowaniadanych wyj�ciowych (okre�lanych w programie rdoc mianem generatorów) i jednastrategia autonomiczna. Wszystkie cztery powi�zane strategie generuj� dokumentacj�w podobnym formacie — znane wszystkim konstrukcje <co�tam> otoczone nawiasami

Page 22: Ruby. Wzorce projektowe

114 Cz��� II • WZORCE PROJEKTOWE W J�ZYKU RUBY

ostrymi </co�tam>3. Ostatnia strategia generuje dane wyj�ciowe na potrzeby poleceniari j�zyka Ruby, które nie przypominaj� ani kodu XML-a, ani kodu HTML-a. Jakwynika z diagramu UML przedstawionego na rysunku 4.2, relacje ��cz�ce poszczególneklasy 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 RIGeneratorgeneruje 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 jednejnadklasy 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 strategiimamy 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 schematuporz�dkowania elementów? Jak nale�a�oby na przyk�ad posortowa� �acuchy wed�ugd�ugo�ci? Wystarczy przekaza� strategi� porównywania obiektów w formie blokukodu:

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�lipierwszy 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 koduprzypomina zachowanie operatora <=>.

PODSUMOWANIEWzorzec projektowy Strategy reprezentuje nieco inn�, opart� na delegowaniu zadapropozycj� rozwi�zywania tego samego problemu, który jest równie� rozwi�zywanyprzez wzorzec Template Method. Zamiast upychania zmiennych cz��ci algorytmuw podklasach, implementujemy ka�d� z wersji tego algorytmu w odr�bnym obiekcie.Mo�emy nast�pnie urozmaica� dzia�ania tego algorytmu przez wskazywanie obiektowikontekstu ró�nych obiektów strategii. Oznacza to, �e o ile jedna strategia na przyk�adgeneruje 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.

Page 23: Ruby. Wzorce projektowe

Rozdzia� 4. • ZAST�POWANIE ALGORYTMU STRATEGI 1115

w formacie PDF; podobnie, jedna strategia mo�e wyznacza� wysoko�� podatku od-prowadzanego przez pracownika etatowego, by inna wylicza�a podatek nale�ny odpracownika 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, albopo prostu przekazywa� obiektowi strategii referencj� do ca�ego obiektu kontekstu.

Bloki kodu j�zyka Ruby, które w istocie maj� posta� kodu opakowywanego w ramachtworzonego 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�lonegozadania. Okazuje si� jednak, �e wykonanie tego zadania wymaga od kontekstuskorzystania z pomocy innego obiektu (okre�lanego mianem strategii). Z bardzopodobnym modelem mamy do czynienia w przypadku wzorca projektowego Ob-server (obserwatora), gdzie obiekt realizuj�cy pewne zadania kieruje wywo�ania dodrugiego obiektu, bez którego jego funkcjonowanie by�oby niemo�liwe.

Okazuje si�, �e jedyn� ró�nic� dziel�c� oba te wzorce jest intencja programisty. Celemwzorca projektowego Strategy jest dostarczenie obiektowi kontekstu innego obiektu,który „wie”, jak wykona� okre�lon� wersj� algorytmu. Zupe�nie inny cel przy�wiecaprogrami�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, �eb�dzie to kolejny rozdzia�).