Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00677 010258 11042431 na godz. na dobę w sumie
100 sposobów na PHP - książka
100 sposobów na PHP - książka
Autor: Liczba stron: 440
Wydawca: Helion Język publikacji: polski
ISBN: 83-246-0426-X Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> webmasterstwo >> php - programowanie
Porównaj ceny (książka, ebook, audiobook).

Zbiór rozwiązań dla twórców dynamicznych witryn WWW

Język PHP zdobył ogromną popularność jako narzędzie do tworzenia dynamicznych witryn WWW, a grono jego użytkowników stale się powiększa. Programiści i projektanci doceniają jego możliwości, szybkość i wygodę. Standardowe już zastosowania języka PHP -- łączenie witryny WWW z bazą danych, przechowywanie treści artykułów w tabelach i obsługa formularzy nie wyczerpują możliwości tej platformy programistycznej. PHP oferuje znacznie więcej -- pozwala między innymi na dynamiczne generowanie grafiki, korzystanie z usług sieciowych i protokołu SOAP oraz przetwarzanie plików XML.

Książka '100 sposobów na PHP' to coś więcej niż kolejny podręcznik tworzenie aplikacji WWW. Znajdziesz w niej mniej znane sposoby wykorzystywania PHP przy budowaniu witryn internetowych. Nauczysz się korzystać z biblioteki PEAR, tworzyć interfejsów użytkownika z wykorzystaniem języka DHTML oraz technologii SVG oraz generować pliki RTF, CSV i XLS. Dowiesz się, jak stosować wzorce projektowe i testować aplikacje wykorzystując testy jednostkowe. Poznasz zasady programowania obiektowego w PHP i tchniesz nowe życie w działające już aplikacje dodając do nich ciekawe 'wodotryski', których przykłady znajdziesz w tej książce.

Poznaj nietypowe zastosowania języka PHP.

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

Darmowy fragment publikacji:

IDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ SPIS TREŒCI SPIS TREŒCI KATALOG KSI¥¯EK KATALOG KSI¥¯EK KATALOG ONLINE KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG TWÓJ KOSZYK TWÓJ KOSZYK DODAJ DO KOSZYKA DODAJ DO KOSZYKA CENNIK I INFORMACJE CENNIK I INFORMACJE ZAMÓW INFORMACJE ZAMÓW INFORMACJE O NOWOŒCIACH O NOWOŒCIACH ZAMÓW CENNIK ZAMÓW CENNIK CZYTELNIA CZYTELNIA FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: helion@helion.pl 100 sposobów na PHP Autor: Jack Herrington T³umaczenie: Rados³aw Meryk ISBN: 83-246-0426-X Tytu³ orygina³u: PHP Hacks Format: B5, stron: 440 Zbiór rozwi¹zañ dla twórców dynamicznych witryn WWW (cid:129) Korzystanie z danych pochodz¹cych z innych witryn WWW (cid:129) Dynamiczne generowanie grafiki i animacji Flash (cid:129) Obs³uga komunikatorów internetowych i protoko³u IRC Jêzyk PHP zdoby³ ogromn¹ popularnoœæ jako narzêdzie do tworzenia dynamicznych witryn WWW, a grono jego u¿ytkowników stale siê powiêksza. Programiœci i projektanci doceniaj¹ jego mo¿liwoœci, szybkoœæ i wygodê. Standardowe ju¿ zastosowania jêzyka PHP — ³¹czenie witryny WWW z baz¹ danych, przechowywanie treœci artyku³ów w tabelach i obs³uga formularzy nie wyczerpuj¹ mo¿liwoœci tej platformy programistycznej. PHP oferuje znacznie wiêcej — pozwala miêdzy innymi na dynamiczne generowanie grafiki, korzystanie z us³ug sieciowych i protoko³u SOAP oraz przetwarzanie plików XML. Ksi¹¿ka „100 sposobów na PHP” to coœ wiêcej ni¿ kolejny podrêcznik tworzenie aplikacji WWW. Znajdziesz w niej mniej znane sposoby wykorzystywania PHP przy budowaniu witryn internetowych. Nauczysz siê korzystaæ z biblioteki PEAR, tworzyæ interfejsów u¿ytkownika z wykorzystaniem jêzyka DHTML oraz technologii SVG oraz generowaæ pliki RTF, CSV i XLS. Dowiesz siê, jak stosowaæ wzorce projektowe i testowaæ aplikacje wykorzystuj¹c testy jednostkowe. Poznasz zasady programowania obiektowego w PHP i tchniesz nowe ¿ycie w dzia³aj¹ce ju¿ aplikacje dodaj¹c do nich ciekawe „wodotryski”, których przyk³ady znajdziesz w tej ksi¹¿ce. (cid:129) Instalacja PHP oraz biblioteki PEAR (cid:129) Projektowanie interfejsów u¿ytkownika (cid:129) £¹czenie PHP z DHTML oraz JavaScript (cid:129) Generowanie grafiki bitmapowej i wektorowej (cid:129) Manipulowanie danymi w bazie za pomoc¹ plików XML (cid:129) £¹czenie aplikacji WWW z GoogleMaps oraz Wikipedi¹ (cid:129) Wykorzystywanie wzorców projektowych (cid:129) Testowanie aplikacji (cid:129) Generowanie animacji Flash (cid:129) Wysy³anie SMS-ów oraz wiadomoœci na serwery IRC Poznaj nietypowe zastosowania jêzyka PHP O autorach ...................................................................................................................................... 9 Przedmowa ................................................................................................................................... 13 Rozdział 1. Instalacja i podstawy ................................................................................................ 21 1. Instalacja PHP .................................................................................................................. 21 2. Instalacja modułów PEAR .............................................................................................. 32 Rozdział 2. Projektowanie aplikacji internetowych ................................................................... 35 3. Tworzenie interfejsu z wykorzystaniem „skórek” ..................................................... 35 4. Tworzenie nawigacji typu breadcrumb ....................................................................... 39 5. Tworzenie ramek na stronach WWW .......................................................................... 43 6. Zastosowanie zakładek w interfejsie aplikacji internetowych ................................. 47 7. Zapewnienie użytkownikom możliwości formatowania stron z wykorzystaniem techniki XSL .................................................................................... 50 8. Tworzenie prostych wykresów HTML ........................................................................ 53 9. Prawidłowe ustawianie rozmiaru znaczników graficznych .................................... 55 10. Wysyłanie wiadomości e-mail w formacie HTML .................................................... 57 Rozdział 3. DHTML ....................................................................................................................... 61 11. Umieszczenie na stronie interaktywnego arkusza kalkulacyjnego ......................... 61 12. Tworzenie wyskakujących wskazówek ....................................................................... 64 13. Tworzenie list w trybie przeciągnij i upuść ................................................................ 66 14. Tworzenie dynamicznych wykresów .......................................................................... 69 15. Podział treści na rozwijane sekcje ................................................................................. 74 16. Tworzenie rozwijanych „samoprzylepnych” karteczek ........................................... 78 17. Tworzenie dynamicznych menu nawigacyjnych ....................................................... 80 18. Dynamiczne ukrywanie kodu JavaScript .................................................................... 83 19. Tworzenie zegara binarnego za pomocą kodu DHTML .......................................... 85 20. Ułatwienie implementacji Ajax za pomocą modułu JSON ....................................... 88 21. Utworzenie pokazu slajdów za pomocą kodu DHTML ........................................... 91 22. Wykorzystanie grafiki wektorowej w PHP ................................................................. 93 Spis treści | 5 23. Tworzenie narzędzia do wybierania kolorów ............................................................ 96 24. Tworzenie grafu łączy .................................................................................................... 98 25. Utworzenie interaktywnego kalendarza ................................................................... 101 26. Tworzenie efektu przewijania map Google .............................................................. 105 Rozdział 4. Grafika ..................................................................................................................... 113 27. Tworzenie miniaturek ................................................................................................... 113 28. Tworzenie atrakcyjnej grafiki za pomocą SVG ......................................................... 115 29. Uproszczenie obsługi grafiki dzięki wykorzystaniu obiektów ............................. 118 30. Podział obrazu na kilka mniejszych ........................................................................... 126 31. Tworzenie wykresów w PHP ...................................................................................... 130 32. Nakładanie obrazów ..................................................................................................... 132 33. Dostęp do zdjęć iPhoto z poziomu PHP ................................................................... 136 Rozdział 5. Bazy danych i XML ................................................................................................. 149 34. Projektowanie lepszego schematu SQL ..................................................................... 149 35. Uniwersalny dostęp do bazy danych ......................................................................... 154 36. Tworzenie dynamicznych obiektów dostępu do bazy danych ................................ 156 37. Generowanie instrukcji CRUD dla baz danych ........................................................ 160 38. Zastosowanie wyrażeń regularnych do łatwego czytania dokumentów XML .. 169 39. Eksportowanie schematu bazy danych w formacie XML ...................................... 172 40. Prosty mechanizm obsługi zapytań do bazy danych w formacie XML ............... 174 41. Generowanie kodu SQL ............................................................................................... 175 42. Generowanie kodu PHP dostępu do bazy danych .................................................. 178 43. Konwersja CSV na PHP ................................................................................................ 184 44. Odczyt danych ze stron WWW ................................................................................... 187 45. Odczytywanie danych z arkuszy Excela wgranych na serwer ................................ 192 46. Ładowanie danych z Excela do bazy danych ........................................................... 196 47. Przeszukiwanie dokumentów programu Microsoft Word .................................... 200 48. Dynamiczne tworzenie dokumentów RTF ............................................................... 203 49. Dynamiczne tworzenie arkuszy Excela ..................................................................... 208 50. Tworzenie kolejki wiadomości .................................................................................... 213 Rozdział 6. Projektowanie aplikacji .......................................................................................... 217 51. Tworzenie modularnych interfejsów ......................................................................... 217 52. Obsługa tekstu Wiki ...................................................................................................... 221 53. Przekształcanie dowolnych obiektów na tablice ...................................................... 224 54. Tworzenie prawidłowego kodu XML ........................................................................ 227 55. Rozwiązanie problemu podwójnego przesyłania .................................................... 230 56. Tworzenie spersonalizowanych raportów ................................................................ 234 57. Tworzenie systemu logowania .................................................................................... 236 6 | Spis treści 58. Zabezpieczenia z wykorzystaniem ról ....................................................................... 241 59. Migracja do haseł MD5 ................................................................................................. 248 60. Zastosowanie modułu mod_rewrite do tworzenia użytecznych adresów URL ........252 61. Utworzenie mechanizmu przekierowania reklam ................................................... 257 62. Wykorzystanie przycisku Buy Now serwisu PayPal .............................................. 260 63. Odczytywanie informacji o lokalizacji użytkowników aplikacji ................................ 269 64. Import informacji z plików vCard .............................................................................. 270 65. Tworzenie plików vCard na podstawie danych aplikacji ...................................... 273 66. Tworzenie koszyka na zakupy .................................................................................... 274 Rozdział 7. Wzorce projektowe ................................................................................................. 283 67. Obserwacja obiektów .................................................................................................... 284 68. Tworzenie obiektów z wykorzystaniem wzorca Fabryka Abstrakcyjna ............. 287 69. Elastyczne tworzenie obiektów z wykorzystaniem wzorca Metoda Fabrykująca ....290 70. Wyodrębnienie kodu konstrukcyjnego za pomocą wzorca Budowniczy ............ 292 71. Oddzielenie części „co” od „jak” za pomocą wzorca Strategia ............................. 296 72. Łączenie dwóch modułów z wykorzystaniem wzorca Adapter ........................... 299 73. Pisanie przenośnego kodu z wykorzystaniem wzorca Most ................................. 302 74. Rozszerzalne przetwarzanie z wykorzystaniem wzorca Łańcuch odpowiedzialności .......................................................................... 305 75. Podział rozbudowanych klas na mniejsze z wykorzystaniem wzorca Kompozyt ....................................................................... 309 76. Uproszczenie interfejsu API z wykorzystaniem wzorca Fasada ........................... 311 77. Tworzenie stałych obiektów za pomocą wzorca Singleton .................................... 315 78. Ułatwienie wykonywania operacji z danymi dzięki zastosowaniu wzorca Wizytator ..................................................................... 318 Rozdział 8. Testowanie .............................................................................................................. 323 79. Testowanie kodu za pomocą testów jednostkowych .............................................. 323 80. Generowanie własnych testów jednostkowych ....................................................... 325 81. Wyszukiwanie niesprawnych łączy ........................................................................... 329 82. Testowanie aplikacji z wykorzystaniem symulowanych użytkowników ........... 331 83. Testowanie aplikacji z wykorzystaniem robotów .................................................... 335 84. Testowanie witryny za pomocą aplikacji typu „pająk” .......................................... 339 85. Automatyczne generowanie dokumentacji ............................................................... 343 Rozdział 9. Alternatywne interfejsy użytkownika .................................................................... 347 86. Tworzenie map z wykorzystaniem systemu MapServer ........................................ 347 87. Tworzenie interfejsów GUI z wykorzystaniem biblioteki GTk ............................. 357 88. Wysyłanie nagłówków RSS do komunikatorów za pomocą protokołu Jabber ....... 360 89. Komunikacja z aplikacją internetową za pomocą IRC ............................................ 367 Spis treści | 7 90. Odczyt źródeł RSS na konsoli PSP ............................................................................. 369 91. Wyszukiwanie w Google według słów kluczowych ............................................... 372 92. Utworzenie nowego interfejsu witryny Amazon.com ............................................ 378 93. Wysyłanie wiadomości SMS za pomocą komunikatorów ..................................... 381 94. Generowanie animacji Flasha ...................................................................................... 385 Rozdział 10. Dla zabawy ............................................................................................................ 395 95. Tworzenie własnych map Google .............................................................................. 395 96. Tworzenie dynamicznych list odtwarzania .............................................................. 400 97. Utworzenie centrum wymiany plików multimedialnych ...................................... 403 98. Sprawdzanie statusu gry sieciowej za pomocą skryptu PHP ................................ 408 99. Wikipedia na konsoli PSP ............................................................................................ 410 100. Gdzie jest lepsza pogoda? ............................................................................................ 417 Skorowidz ................................................................................................................................... 421 8 | Spis treści Obserwacja obiektów SPOSÓB 67. R O Z D Z I A Ł S I Ó D M Y Sposoby 67. – 78. W 1994 roku Erich Gamma, Richard Helm, Ralph Johnson i John Vlissides opublikowali książkę pt. Design Patterns1 (Addison-Wesley). Z powodu doskonałej treści publikacja bardzo szybko została zaliczona do klasyki literatury informatycznej. Jednym z jej osiągnięć było wypromowanie nowego metajęzyka w dziedzinie inżynierii i architektury systemów. Główna idea książki — opracowanie zbioru wzorców struktury obiektów — została za- pożyczona z budownictwa i przystosowana do programowania. Zbiór 40 wzorców projektowych zaprezentowanych w książce Design Patterns to efekt wielu lat doświadczeń. Każdy z nich opisano w formie neutralnej pod względem języka. Większość można zastosować w każdym środowisku projektowym. Niektóre wzorce projektowe, na przykład Iterator, opracowano specjalnie po to, by uzupełnić braki języków programowania (w przypadku wzorca Iterator chodzi o język C++). W PHP jest wbudowana implementacja tego wzorca — konstrukcja foreach. Wzorce projektowe nie były zbyt często wykorzystywane w PHP. Przed wydaniem PHP w wersji 5 język PHP i jego środowisko projektowe nie były traktowane w branży pro- gramistów poważnie. Obecnie, dzięki rozbudowanemu modelowi obiektowemu, dobrym środowiskom IDE i dużej popularności języka wśród programistów, branża zaczyna dostrzegać PHP. Zastosowanie wzorców projektowych w PHP opisano w niektórych najnowszych wydawnictwach poświęconych temu językowi. Uważam, że warto poświęcić im nieco uwagi także w tej książce. W swej pracy postanowiłem odwoływać się do książki Design Patterns. Wybrałem z niej podzbiór wzorców do zaimplementowania. Wzorce te, wraz z ich implementacją, dają solidne podstawy architektury systemów. Mogą być także inspiracją do opracowywania własnego kodu. 1 Polskie wydanie Wzorce projektowe — Wydawnictwa Naukowo-Techniczne 2005 — przyp. tłum. Wzorce projektowe | 283 SPOSÓB 67. Obserwacja obiektów S P O S Ó B 67. Obserwacja obiektów Zastosowanie wzorca Obserwator do luźnego wiązania obiektów. Luźne wiązanie obiektów (ang. loose coupling), pomimo że niewiele osób dobrze inter- pretuje ten termin, ma kluczowe znaczenie dla każdego projektu na dużą skalę. Czy zda- rzyło się Wam wprowadzić niewielką modyfikację w projekcie, w której wyniku trzeba było zmienić w nim niemal wszystko? Taka sytuacja zdarza się nader często, a jej przy- czyną jest ścisłe wiązanie pomiędzy modułami programu. Jeśli jeden z nich przestaje działać, podobnie dzieje się z resztą. Wzorzec Obserwator rozluźnia powiązania pomiędzy obiektami dzięki zastosowaniu prostszego kontraktu. Obiekt może być obserwowany dzięki udostępnieniu mechani- zmu rejestracji. W przypadku, gdy obserwowany obiekt się zmienia, informuje o tym obiekty obserwujące za pomocą obiektu powiadamiającego. Obserwowanego obiektu nie interesuje ani sposób, ani powód, dla którego jest obserwowany. Nie wie nawet tego, jakie typy obiektów go obserwują. Co więcej, obiektów obserwujących zazwyczaj nie interesuje sposób lub powód modyfikacji obiektu. Jedyne, co śledzą, to zmiany. Klasycznym przykładem wzorca Obserwator jest kod obsługi okna dialogowego, który obserwuje stan pola wyboru. Dla pola wyboru nie ma znaczenia, czy obserwuje go jeden obiekt czy tysiąc. Jeśli zmieni się jego stan, po prostu wysyła informację. Z kolei dla okna dialogowego nie ma znaczenia sposób implementacji pola wyboru. Istotny jest tylko jego stan oraz uzyskanie powiadomienia w przypadku, gdy się zmieni. W podrozdziale zademonstruję wzorzec Obserwator na przykładzie listy klientów, którą można obserwować. Obiekt reprezentuje tabelę klientów w bazie danych. W przypadku dodania nowych klientów obiekt CustomerList wysyła powiadomienie. Do zaimple- mentowania obserwacji obiekt CustomerList wykorzystuje klasę SubscriptionList. Obiekty nasłuchujące to egzemplarze klasy SubscriptionList, które inne obiekty wykorzystują do zarejestrowania się w obiekcie CustomerList. Obiekty te używają metody add() w celu dodania się do listy, natomiast obiekt CustomerList wykorzy- stuje metodę invoke() w celu wysłania komunikatu do obiektów nasłuchujących. Dla obiektu CustomerObject nie ma znaczenia, czy jest tysiąc obiektów nasłuchujących czy nie ma żadnego. Ciekawą własnością wzorca Obserwator jest fakt, iż obiekty nasłu- chujące nie komunikują się w sposób bezpośredni ani nie zależą od obiektu CustomerList. Obiekty nasłuchujące są odizolowane od klientów za pomocą klasy SubscriptionList. W pokazanym przykładzie zdefiniujemy jeden obiekt nasłuchujący: Log, którego działanie polega na wyświetlaniu na konsoli komunikatów przesyłanych przez obiekt Customer- List. Powiązania pomiędzy obiektami zaprezentowano na rysunku 7.1. 284 | Wzorce projektowe Obserwacja obiektów SPOSÓB 67. Rysunek 7.1. Obiekty CustomerList oraz związany z nim obiekt SubscriptionList wraz z obiektem Log Kod Kod pokazany na listingu 7.1 należy zapisać w pliku observer.php. Listing 7.1. Przykład zastosowania wzorca projektowego Obserwator ?php class Log { public function message( $sender, $messageType, $data ) { print $messageType. - .$data. ; } } class SubscriptionList { var $list = array(); public function add( $obj, $method ) { $this- list []= array( $obj, $method ); } public function invoke() { $args = func_get_args(); foreach( $this- list as $l ) { call_user_func_array( $l, $args ); } } } class CustomerList { public $listeners; public function CustomerList() { $this- listeners = new SubscriptionList(); } public function addUser( $user ) { $this- listeners- invoke( $this, add , $user ); } } Wzorce projektowe | 285 SPOSÓB 67. Obserwacja obiektów $l = new Log(); $cl = new CustomerList(); $cl- listeners- add( $l, message ); $cl- addUser( starbuck ); ? Wykorzystanie sposobu Powyższy kod można uruchomić w wierszu polecenia w następujący sposób: php observer.php add - starbuck Kod najpierw tworzy listę klientów oraz obiekt Log. Następnie obiekt Log wykonuje subskrypcję listy klientów za pomocą metody add(). Ostatnia czynność to dodanie użytkownika do listy klientów. Powoduje to wysłanie wiadomości do obiektów nasłu- chujących — w tym przypadku do obiektu Log, który wyświetla komunikat o dodaniu nowego klienta. Bez trudu można rozszerzyć zaprezentowany kod i skonfigurować konto klienta po do- daniu lub, na przykład, wysłać e-mail do nowego użytkownika — obie te operacje moż- na wykonać bez konieczności modyfikacji kodu obiektu CustomerList. Właśnie na tym polega luźne wiązanie obiektów i dlatego wzorzec projektowy Obserwator jest taki ważny. Istnieje bardzo wiele zastosowań wzorca projektowego Obserwator w programowaniu. Wykorzystuje się go, między innymi, w systemach okienkowych do implementacji me- chanizmu zdarzeń (ang. events). Niektóre firmy, na przykład Tibco, tworzą cały model działania swoich przedsiębiorstw w oparciu o wzorzec Obserwator. Wykorzystują go do łączenia dużych podsystemów funkcjonalnych, takich jak Kadry i Płace. W systemach baz danych wzorzec Obserwator można wykorzystać do wywoływania kodu związanego z wyzwalaczami, które uaktywniają się w przypadku, gdy w bazie danych zostaną zmodyfikowane pewne typy rekordów. Mechanizm wykorzystujący wzorzec Obserwator przydaje się również w sytuacjach, gdy mamy świadomość, że zmiana stanu będzie istotna, ale jeszcze nie wiemy, gdzie te informacje wykorzystamy. Obiekty nasłuchujące można zaimplementować później i nie trzeba ich wiązać z obserwowanym obiektem. Potencjalnym problemem wzorca projektowego Obserwator są pętle nieskończone. Mogą się zdarzyć, gdy obiekty obserwujące system jednocześnie go modyfikują. Na przykład rozwijane pole kombi modyfikuje wartość i informuje o tym strukturę danych. Struktura danych powiadamia rozwijane pole kombi, że wartość się zmieniła. Wtedy rozwijane pole kombi modyfikuje swoją wartość i wysyła kolejne powiadomienie do struktury da- nych itd. Najprostszym sposobem rozwiązania tego problemu jest wykluczenie wystą- pienia rekurencji w kodzie obsługi pola kombi. Obiekt powinien zignorować komunikat od struktury danych, jeśli właśnie powiadamia strukturę danych o swojej nowej wartości. 286 | Wzorce projektowe Tworzenie obiektów z wykorzystaniem wzorca Fabryka Abstrakcyjna SPOSÓB 68. Zobacz też „Przekształcanie dowolnych obiektów na tablice” [Sposób 53.]. · „Tworzenie kolejki wiadomości” [Sposób 50.]. · S P O S Ó B 68. Tworzenie obiektów z wykorzystaniem wzorca Fabryka Abstrakcyjna Wykorzystanie wzorca projektowego Fabryka Abstrakcyjna do śledzenia typu tworzonych obiektów. Wzorzec projektowy Fabryka Abstrakcyjna (ang. Abstract Factory) to maszyna do produk- cji wzorców projektowych. Wystarczy zdefiniować to, czego chcemy, a wzorzec zadba o utworzenie obiektów na podstawie wprowadzonych kryteriów. Zaletą wzorca jest możliwość modyfikacji typu tworzonych obiektów poprzez modyfikację „fabryki”. W prostym przykładzie zaprezentowanym w tym podrozdziale utworzymy obiekty Record, z których każdy będzie miał swój identyfikator, imię i nazwisko. Związki po- między poszczególnymi klasami pokazano na rysunku 7.2. Rysunek 7.2. Klasy Record i RecordFactory Obiekty-fabryki często tworzą więcej niż jeden typ obiektów. Dla uproszczenia przykładu ograniczyłem obiekt-fabrykę do tworzenia tylko jednego typu obiektów. W PHP nie można rygorystycznie wymusić tworzenia obiektów określonego typu wy- łącznie przez obiekt-fabrykę. Jeśli jednak będziemy stosowali obiekt-fabrykę stosunkowo często, inżynierowie kopiując i wklejając nasz kod, będą w efekcie stosowali obiekt- fabrykę. Szybko stanie się on standardem de facto tworzenia różnych typów obiektów. Wzorce projektowe | 287 SPOSÓB 68. Tworzenie obiektów z wykorzystaniem wzorca Fabryka Abstrakcyjna Kod Kod pokazany na listingu 7.2 zapiszemy w pliku abs_factory.php. Listing 7.2. Zastosowanie wzorca projektowego Fabryka Abstrakcyjna ?php class Record { public $id = null; public $first = null; public $last = null; public function __construct( $id, $first, $last ) { $this- id = $id; $this- first = $first; $this- last = $last; } } class USRecord extends Record { public $addr1 = null; public $addr2 = null; public $city = null; public $state = null; public $zip = null; public function __construct( $id, $first, $last, $addr1, $addr2, $city, $state, $zip ) { parent::__construct( $id, $first, $last ); $this- addr1 = $addr1; $this- addr2 = $addr2; $this- city = $city; $this- state = $state; $this- zip = $zip; } } class ForeignRecord extends Record { public $addr1 = null; public $addr2 = null; public $city = null; public $state = null; public $postal = null; public $country = null; public function __construct( $id, $first, $last, $addr1, $addr2, $city, $state, $postal, $country ) { parent::__construct( $id, $first, $last ); $this- addr1 = $addr1; $this- addr2 = $addr2; $this- city = $city; $this- state = $state; $this- postal = $postal; $this- country = $country; } } 288 | Wzorce projektowe Tworzenie obiektów z wykorzystaniem wzorca Fabryka Abstrakcyjna SPOSÓB 68. class RecordFactory { public static function createRecord( $id, $first, $last, $addr1, $addr2, $city, $state, $postal, $country ) { if ( strlen( $country ) 0 $country != USA ) return new ForeignRecord( $id, $first, $last, $addr1, $addr2, $city, $state, $postal, $country ); else return new USRecord( $id, $first, $last, $addr1, $addr2, $city, $state, $postal ); } } function readRecords() { $records = array(); $records []= RecordFactory::createRecord( 1, Jack , Herrington , 4250 San Jaquin Dr. , , Los Angeles , CA , 90210 , ); $records []= RecordFactory::createRecord( 1, Maria , Kowalska , Pstrowskiego 4 , , Malbork , pomorskie , 82-200 , Polska ); return $records; } $records = readRecords(); foreach( $records as $r ) { $class = new ReflectionClass( $r ); print $class- getName(). - .$r- id. - .$r- first. - .$r- last. ; } ? W pierwszej części kodu zaimplementowano klasę bazową Record oraz klasy pochodne USRecord i ForeignRecord. Są to stosunkowo proste klasy opakowujące dla struktur danych. Klasa-fabryka może tworzyć zarówno obiekty USRecord, jak ForeignRecord w zależności od danych, które zostaną do niej przekazane. Kod testujący na końcu skryptu dodaje kilka rekordów, po czym wyświetla ich typ oraz niektóre dane. Wykorzystanie sposobu Do uruchomienia przykładu zastosujemy interpreter PHP działający w wierszu polecenia w następujący sposób: php abs_factory.php USRecord - 1 - Jack - Herrington ForeignRecord - 1 - Maria - Kowalska W aplikacji bazodanowej w PHP można zastosować wzorzec projektowy Fabryka Abstrak- cyjna na kilka sposobów: Wzorce projektowe | 289 SPOSÓB 69. Elastyczne tworzenie obiektów z wykorzystaniem wzorca Metoda Fabrykująca Tworzenie obiektu bazy danych Obiekt-fabryka tworzy wszystkie typy obiektowe powiązane z poszczególnymi tabelami w bazie danych. Tworzenie przenośnych obiektów Obiekt-fabryka tworzy różne obiekty w zależności od typu systemu operacyjnego, w którym działa kod, bądź od typów baz danych, z którymi aplikacja się łączy. Tworzenie według standardu Aplikacja obsługuje różnorodne standardy formatów plików i wykorzystuje obiekt-fabrykę do tworzenia obiektów odpowiednich dla poszczególnych typów plików. Obiekty czytające pliki mogą się zarejestrować w obiekcie-fabryce w celu dodania obsługi plików bez konieczności modyfikacji klientów. Wykorzystywanie wzorców projektowych przez pewien czas pozwala programiście na uzyskanie wyczucia co do tego, kiedy warto zastosować określony wzorzec. Wzorzec Fabryka Abstrakcyjna stosuje się w przypadku tworzenia dużej liczby obiektów różnych typów. Jak można się przekonać, zmiany typów tworzonych obiektów lub sposobu ich tworzenia często powodują konieczność wielu modyfikacji w kodzie. W przypadku za- stosowania klasy-fabryki zmianę trzeba wprowadzić tylko w jednym miejscu. Zobacz też „Elastyczne tworzenie obiektów z wykorzystaniem wzorca Metoda Fabrykująca” · [Sposób 69.]. S P O S Ó B 69. Elastyczne tworzenie obiektów z wykorzystaniem wzorca Metoda Fabrykująca Wykorzystanie wzorca Metoda Fabrykująca podczas tworzenia obiektów w celu umożliwienia klasom pochodnym modyfikacji typów tworzonych obiektów. Z wzorcem Fabryka Abstrakcyjna jest blisko związany wzorzec Metoda Fabrykująca. Jego działanie jest dość oczywiste. Jeśli mamy klasę, która tworzy dużą liczbę obiektów, mo- żemy wykorzystać metody chronione hermetyzujące operacje tworzenia. W ten sposób klasy pochodne, w celu utworzenia różnych typów obiektów, mogą przesłonić metody chronione klasy-fabryki. W pokazanym przykładzie klasa RecordReader zamiast skorzystania z klasy-fabryki wykorzystuje metodę NewRecord(). W ten sposób klasy pochodne klasy RecordReader mogą modyfikować typ tworzonych obiektów Record poprzez przesłonięcie metody newRecord(). Sytuację tę graficznie przedstawiono na rysunku 7.3. Kod Kod pokazany na listingu 7.3 zapiszemy w pliku factory_method.php. 290 | Wzorce projektowe Elastyczne tworzenie obiektów z wykorzystaniem wzorca Metoda Fabrykująca SPOSÓB 69. Rysunek 7.3. Związki pomiędzy klasami RecordReader i Record Listing 7.3. Przykład metod fabrycznych klasy ?php class Record { public $id = null; public $first = null; public $last = null; public function Record( $id, $first, $last ) { $this- id = $id; $this- first = $first; $this- last = $last; } } class RecordReader { function readRecords() { $records = array(); $records []= $this- newRecord( 1, Jack , Herrington ); $records []= $this- newRecord( 2, Lori , Herrington ); $records []= $this- newRecord( 3, Megan , Herrington ); return $records; } protected function newRecord( $id, $first, $last ) { return new Record( $id, $first, $last ); } } $rr = new RecordReader(); $records = $rr- readRecords(); foreach( $records as $r ) { print $r- id. - .$r- first. - .$r- last. ; } ? Wzorce projektowe | 291 SPOSÓB 70. Wyodrębnienie kodu konstrukcyjnego za pomocą wzorca Budowniczy Wykorzystanie sposobu Zaprezentowany kod uruchamia się w wierszu polecenia w następujący sposób: php factory_method.php 1 - Jack - Herrington 2 - Lori - Herrington 3 - Megan - Herrington Po utworzeniu egzemplarza obiektu RecordReader następuje wywołanie jego metody readRecords(), która z kolei wywołuje metodę newRecord w celu utworzenia wszyst- kich obiektów Record. Utworzone obiekty są następnie wyświetlane na konsoli za po- mocą pętli foreach. W najbardziej widoczny sposób wzorzec Metoda Fabrykująca zastosowano w interfejsie API XML DOM organizacji W3C instalowanym w ramach bazowej instalacji PHP 5. Obiekt DOMDocument, który spełnia rolę korzenia każdego drzewa DOM, zawiera zbiór metod-fabryk: createElement(), createAttrribute(), createTextNode() itd. Implementacje pochodne od obiektu DOMDocument mogą przesłaniać te metody w celu zmiany obiektów tworzonych podczas ładowania drzew XML z dysku, zmiennych tek- stowych lub tworzonych „w locie”. Podobnie jak w przypadku wzorca Fabryka Abstrakcyjna najważniejszą przesłanką do wykorzystania wzorca Metoda Fabrykująca jest sytuacja, gdy piszemy dużo kodu tworzą- cego obiekty. Dzięki zastosowaniu wzorca Fabryka Abstrakcyjna bądź Method Factory zy- skujemy pewność, że jeśli zmieni się typ obiektów, który chcemy tworzyć, lub sposób ich tworzenia, zmiany w kodzie będą minimalne. Zobacz też „Tworzenie obiektów z wykorzystaniem wzorca Fabryka Abstrakcyjna” [Sposób 68.]. · S P O S Ó B 70. Wyodrębnienie kodu konstrukcyjnego za pomocą wzorca Budowniczy Wykorzystanie wzorca Budowniczy do wyodrębnienia kodu, który wykonuje rutynowe operacje konstrukcyjne, takie jak tworzenie dokumentów HTML lub tekstu wiadomości e-mail. Wielokrotnie odnoszę wrażenie, że kod, który coś tworzy, jest najbardziej elegancki w ca- łym systemie. Myślę, że jest tak dlatego, że poświęciłem rok na pisanie książki o genero- waniu kodu, która w całości jest poświęcona kodowi konstrukcyjnemu. Chciałbym dodać, że książka Code Generation in Action jest ciągle dostępna i może być doskonałym prezentem świątecznym dla przyjaciół lub członków rodziny. 292 | Wzorce projektowe Wyodrębnienie kodu konstrukcyjnego za pomocą wzorca Budowniczy SPOSÓB 70. Przykładem kodu konstrukcyjnego może być kod odczytujący dokument XML z dysku i tworzący jego reprezentację w pamięci. Innym może być moduł tworzący wiadomości e-mail przypominające klientom o tym, że upłynął termin płatności. W niniejszym podrozdziale pokażę przykład tworzenia wiadomości o spóźnionych płat- nościach. Zrobię to jednak sposobem: wykorzystam wzorzec Budowniczy, dzięki czemu kod tworzący wiadomość w formacie HTML będzie można wykorzystać do tworzenia wiadomości w formacie XHTML lub tekstowym. W kodzie, który pisze wiadomość o spóźnionej płatności, zamierzam wykorzystać obiekt-konstruktora zamiast bezpośredniego tworzenia ciągu znaków. Obiekt ten będzie zawierał szereg metod, tak jak pokazano na rysunku 7.4. Kod tworzący wiadomość jest umieszczony pomiędzy wywołaniami metod startBody() oraz endBody(). Metoda addText() dodaje tekst wiadomości, natomiast addBreak() — znak zakończenia wiersza. Rysunek 7.4. Hierarchia obiektów tworzących wiadomości Klasa abstrakcyjna OutputBuilder ma kilka zmaterializowanych egzemplarzy. Jednym z nich jest HTMLBuilder tworzący kod HTML. Klasą jej pochodną jest XHTMLBuilder — klasa modyfikująca działanie klasy nadrzędnej w sposób wystarczający do utworze- nia wyniku zgodnego z XHTML-em. Ostatnią klasą jest TextBuilder, która tworzy re- prezentację wiadomości w formacie zwykłego tekstu. Wzorce projektowe | 293 SPOSÓB 70. Wyodrębnienie kodu konstrukcyjnego za pomocą wzorca Budowniczy Kod Kod pokazany na listingu 7.4 zapiszemy w pliku builder.php. Listing 7.4. Zbiór przykładowych klas konstrukcyjnych i kod testowy ?php abstract class OutputBuilder { abstract function getOutput(); abstract function startBody(); abstract function endBody(); abstract function addText( $text ); abstract function addBreak(); } class HTMLBuilder extends OutputBuilder { private $buffer = ; public function getOutput() { return html .$this- buffer. /html ; } public function startBody() { $this- add( body ); } public function endBody() { $this- add( /body ); } public function addText( $text ) { $this- add( $text ); } public function addBreak() { $this- add( br ); } protected function add( $text ) { $this- buffer .= $text; } } class XHTMLBuilder extends HTMLBuilder { public function addBreak() { $this- add( br / ); } } class TextBuilder extends OutputBuilder { private $buffer = ; public function getOutput() { return $this- buffer. ; } public function startBody() { } public function endBody() { } public function addText( $text ) { $this- add( $text ); } public function addBreak() { $this- add( ); } protected function add( $text ) { $this- buffer .= $text; } } function buildDocument( $builder ) { $builder- startBody(); $builder- addText( Jack, ); $builder- addBreak(); $builder- addText( Jesteś nam winien 10 000 zł. Życzymy MIŁEGO dnia. ); $builder- endBody(); } 294 | Wzorce projektowe Wyodrębnienie kodu konstrukcyjnego za pomocą wzorca Budowniczy SPOSÓB 70. print HTML: ; $html = new HTMLBuilder(); buildDocument( $html ); echo( $html- getOutput() ); print XHTML: ; $xhtml = new XHTMLBuilder(); buildDocument( $xhtml ); echo( $xhtml- getOutput() ); print Tekst: ; $text = new TextBuilder(); buildDocument( $text ); echo( $text- getOutput() ); ? Wykorzystanie sposobu Do uruchomienia kodu wykorzystamy interpreter PHP działający w wierszu polecenia: php builder.php HTML: html body Jack, br Jesteś nam winien 10 000 zł. Życzymy MIŁEGO dnia. /body /html XHTML: html body Jack, br / Jesteś nam winien 10 000 zł. Życzymy MIŁEGO dnia. /body /html Tekst: Jack, Jesteś nam winien 10 000 zł. Życzymy MIŁEGO dnia. Wyświetlił się wynik działania trzech obiektów konstrukcyjnych. Pierwszy to wersja wiadomości w formacie HTML z prawidłowymi znacznikami HTML oraz znacznikiem br . Kod konstrukcyjny dla XHTML-a nieco zmodyfikował wiadomość — przekształ- cił znacznik br na br / . Wersja tekstowa to po prostu zwykły tekst. Znak końca wiersza zastąpiono znakiem powrotu karetki. Na początku kodu znajduje się definicja klasy abstrakcyjnej OutputBuilder, za którą występują poszczególne egzemplarze klas dla różnych formatów wyniku. Obiekt kon- struktora wykorzystano w funkcji buildDocument(), która tworzy wiadomość. Kod na końcu skryptu to testy funkcji buildDocument() dla każdego z typów obiektów kon- strukcyjnych. Wzorce projektowe | 295 SPOSÓB 71. Oddzielenie części „co” od „jak” za pomocą wzorca Strategia Wzorzec Budowniczy w aplikacji internetowej w PHP można wykorzystać w kilku miejscach: Odczyt plików W operacjach przetwarzania plików można wykorzystać wzorzec Budowniczy do oddzielenia operacji analizy treści pliku od tworzenia struktur danych w pamięci z danymi z pliku. Zapis plików Zgodnie z tym, co pokazałem w tym podrozdziale, wzorzec Budowniczy można wykorzystać do tworzenia wielu formatów wynikowych za pomocą jednego systemu tworzenia dokumentów. Generowanie kodu Wzorzec Budowniczy można zastosować do generowania kodu w wielu językach za pomocą jednego systemu generującego. W środowisku .NET wykorzystuje się wzorzec Budowniczy do tworzenia kodu HTML strony wynikowej, tak aby za pomocą tej samej konstrukcji sterującej generować różne odmiany kodu HTML w zależności od typu przeglądarki żądającej strony. S P O S Ó B 71. Oddzielenie części „co” od „jak” za pomocą wzorca Strategia Wykorzystanie wzorca Strategia w celu oddzielenia kodu przeglądającego struktury danych od kodu, który je przetwarza. Wzorzec projektowy Strategia można wykorzystać do wyodrębnienia kodu przetwarzają- cego obiekty. Pozwala to na uniezależnienie sposobu przetwarzania kodu od jego lo- kalizacji. W podrozdziale posłużę się aplikacją do wyboru samochodu. Skrypt będzie polecał sa- mochód na podstawie wprowadzonych kryteriów wyszukiwania. W przykładzie wpro- wadzę specyfikację samochodu idealnego, a kod wybierze egzemplarz, który najbardziej pasuje do moich marzeń. Wielką zaletą wzorca Strategia jest możliwość modyfikacji kodu porównującego samochody w sposób niezależny od kodu wybierającego samochód. Diagram UML dla sposobu pokazanego w tym podrozdziale pokazano na rysunku 7.5. Obiekt CarChooser wykorzystuje obiekt CarWeighter w celu porównania każdego z samochodów z idealnym modelem. Następnie skrypt zwraca do klienta najlepszy samochód. Kod Kod pokazany na listingu 7.5 zapiszemy w pliku strategy.php. 296 | Wzorce projektowe Oddzielenie części „co” od „jak” za pomocą wzorca Strategia SPOSÓB 71. Rysunek 7.5. Relacje pomiędzy obiektami CarChooser, CarWeighter i Car Listing 7.5. Zastosowanie wzorca Strategia ?php class Car { public $name; public $speed; public $looks; public $mileage; public function Car( $name, $speed, $looks, $mileage ) { $this- name = $name; $this- speed = $speed; $this- looks = $looks; $this- mileage = $mileage; } } class CarWeighter { private function diff( $a, $b ) { return abs( $a - $b ); } public function weight( $a, $b ) { $d = 0; $d += $this- diff( $a- speed, $b- speed ); $d += $this- diff( $a- looks, $b- looks ); $d += $this- diff( $a- mileage, $b- mileage ); return ( 0 - $d ); } } class CarChooser { private $ideal; private $alg; function CarChooser( $ideal, $alg ) { Wzorce projektowe | 297 SPOSÓB 71. Oddzielenie części „co” od „jak” za pomocą wzorca Strategia $this- ideal = $ideal; $this- alg = $alg; } public function choose( $carlist ) { $minrank = null; $found = null; $alg = $this- alg; foreach( $carlist as $car ) { $rank = $alg- weight( $this- ideal, $car ); if ( !isset( $minrank ) ) $minrank = $rank; if ( $rank = $minrank ) { $minrank = $rank; $found = $car; } } return $found; } } function pickCar( $car ) { $carlist = array(); $carlist []= new Car( rakieta , 90, 30, 10 ); $carlist []= new Car( rodzinny , 45, 30, 55 ); $carlist []= new Car( ładny , 40, 90, 10 ); $carlist []= new Car( ekonomiczny , 40, 40, 90 ); $cw = new CarWeighter(); $cc = new CarChooser( $car, $cw ); $found = $cc- choose( $carlist ); echo( $found- name. ); } pickCar( new Car( idealny , 80, 40, 10 ) ); pickCar( new Car( idealny , 40, 90, 10 ) ); ? Na początku skryptu zdefiniowałem klasę Car zawierającą nazwę samochodu oraz oce- ny dla szybkości, wyglądu i przebiegu. Każda z ocen mieści się w zakresie od 0 do 100 (głównie dlatego, aby obliczenia były proste). Następnie umieściłem definicję klasy CarWeighter, która porównuje dwa samochody i zwraca ocenę porównania. Na końcu zdefiniowałem klasę CarChooser wykorzystującą klasę CarWeighter do wyboru naj- lepszego samochodu na podstawie pewnych kryteriów wejściowych. Funkcja pick- Car() tworzy zbiór samochodów, a następnie wykorzystuje obiekt CarChooser do wyboru z listy samochodu, który najlepiej spełnia kryteria (przekazane za pomocą obiektu Car). Kod testowy umieszczony na końcu skryptu to żądanie wyboru dwóch samochodów — jednego, który ma wysoką ocenę szybkości i drugiego, który ładnie wygląda. 298 | Wzorce projektowe Łączenie dwóch modułów z wykorzystaniem wzorca Adapter SPOSÓB 72. Wykorzystanie sposobu Do uruchomienia kodu wykorzystamy interpreter PHP działający w wierszu polecenia: php strategy.php rakieta ładny Z uzyskanego wyniku widać, że samochód, jaki aplikacja poleca mi w przypadku, gdy chodzi mi o szybkość, nazywa się rakieta (doskonałe określenie). W przypadku, gdy inte- resuje mnie coś bardziej seksownego, aplikacja proponuje samochód ładny — świetnie! Kod, który wyciąga wniosek dotyczący tego, czy samochód spełnia kryteria, jest całko- wicie oddzielony od kodu, który przeszukuje listę samochodów i wybiera z niej jeden pojazd. Algorytm porównujący samochód z wprowadzonymi kryteriami można zmody- fikować niezależnie od kodu wybierającego samochód z posortowanej listy. Na przykład w algorytmie porównującym samochody można uwzględnić marki, którymi ostatnio interesowaliśmy się, lub te, których w ostatnim czasie byliśmy posiadaczami. Można rów- nież zmodyfikować kod wybierający samochody tak, by proponował trzy z początku listy. W ten sposób użytkownik miałby dodatkowe możliwości wyboru. S P O S Ó B 72. Łączenie dwóch modułów z wykorzystaniem wzorca Adapter Wykorzystanie klasy-adaptera do przenoszenia danych pomiędzy dwoma modułami w sytuacji, gdy nie chcemy modyfikować interfejsu API żadnego z modułów. Czasami trzeba pobrać dane z dwóch obiektów, z których każdy wykorzystuje inny format. Modyfikacja jednego lub drugiego formatu nie wchodzi w rachubę, ponieważ powodowałaby konieczność wprowadzania wielu dodatkowych zmian w pozostałej części kodu. Jednym z rozwiązań tego problemu jest wykorzystanie klasy-adaptera. Jest to klasa, która potrafi interpretować obie strony transmisji danych i przystosowuje jeden obiekt do komunikacji z drugim. Klasa adapter zademonstrowana w tym podrozdziale przystosowuje dane pochodzące z fikcyjnej bazy danych do wykorzystania przez mechanizm tworzenia wykresów tek- stowych. Na rysunku 7.6 pokazano obiekt RecordGraphAdapter umieszczony pomiędzy obiektem TextGraph po lewej stronie a obiektem RecordList po prawej. Obiekt Text- Graph w czytelny sposób specyfikuje format danych za pomocą klasy abstrakcyjnej TextDataSource. RecordList to klasa-kontener zawierająca listę obiektów Record. W każdym z nich są zapisane dane dotyczące nazwiska (name), wieku (age) i pensji (salary). W pokazanym przykładzie utworzymy wykres pensji. Zadaniem klasy-adaptera jest po- branie danych z obiektu RecordList i przekształcenie ich na postać możliwą do przetworzenia przez obiekt TextGraph. W tym celu dane zostaną zapisane jako obiekty typu TextGraphDataSource. Wzorce projektowe | 299 SPOSÓB 72. Łączenie dwóch modułów z wykorzystaniem wzorca Adapter Rysunek 7.6. Adapter umieszczony pomiędzy kodem tworzącym wykresy a danymi Kod Kod pokazany na listingu 7.6 zapiszemy w pliku adapter.php. Listing 7.6. Przykład wykorzystania wzorca Adapter do tworzenia tekstowego wykresu ?php abstract class TextGraphDataSource { abstract function getCount(); abstract function getName( $row ); abstract function getValue( $row ); } class TextGraph { private $data; private $dmin; private $dmax; public function TextGraph( $data ) { $this- data = $data; } protected function calculateMinMax() { $this- dmin = 100000; $this- dmax = -100000; for( $r = 0; $r $this- data- getCount(); $r++ ) { $v = $this- data- getValue( $r ); if ( $v $this- dmin ) { $this- dmin = $v; } if ( $v $this- dmax ) { $this- dmax = $v; } } } public function render() { $this- calculateMinMax(); $ratio = 40 / ( $this- dmax - $this- dmin ); 300 | Wzorce projektowe Łączenie dwóch modułów z wykorzystaniem wzorca Adapter SPOSÓB 72. for( $r = 0; $r $this- data- getCount(); $r++ ) { $n = $this- data- getName( $r ); $v = $this- data- getValue( $r ); $s = ( $v - $this- dmin ) * $ratio; echo( sprintf( 10s : , $n ) ); for( $st = 0; $st $s; $st++ ) { echo( * ); } echo( ); } } } class Record { public $name; public $age; public $salary; public function Record( $name, $age, $salary ) { $this- name = $name; $this- age = $age; $this- salary = $salary; } } class RecordList { private $records = array(); public function RecordList() { $this- records []= new Record( Janusz , 23, 26000 ); $this- records []= new Record( Beata , 24, 29000 ); $this- records []= new Record( Stefania , 28, 42000 ); $this- records []= new Record( Jerzy , 28, 120000 ); $this- records []= new Record( Grzegorz , 43, 204000 ); } public function getRecords() { return $this- records; } } class RecordGraphAdapter extends TextGraphDataSource { private $records; public function RecordGraphAdapter( $rl ) { $this- records = $rl- getRecords(); } public function getCount( ) { return count( $this- records ); } public function getName( $row ) { return $this- records[ $row ]- name; } public function getValue( $row ) { return $this- records[ $row ]- salary; } } Wzorce projektowe | 301 SPOSÓB 73. Pisanie przenośnego kodu z wykorzystaniem wzorca Most $rl = new RecordList(); $ga = new RecordGraphAdapter( $rl ); $tg = new TextGraph( $ga ); $tg- render(); ? Początek skryptu to kod odpowiedzialny za tworzenie wykresu. Zdefiniowano w nim klasę abstrakcyjną TextGraphDataSource oraz klasę TextGraph wykorzystującą klasę TextGraphDataSource jako format danych. W środkowej części skryptu zdefiniowa- no klasy Record i RecordList (zawierające dane do utworzenia wykresu). W trzeciej części zdefiniowano klasę RecordGraphAdapter, która przystosowuje klasę Record- List do wykorzystania jako źródło danych wykresu. Kod testowy na początku skryptu najpierw tworzy obiekt RecordList, a następnie obiekt-adapter oraz obiekt TextGraph, który odwołuje się do adaptera. Wykres tworzy się poprzez odczyt danych z adaptera. Wykorzystanie sposobu Do uruchomienia kodu wykorzystamy interpreter PHP działający w wierszu polecenia: php adapter.php Janusz : Beata : * Stefania : **** Jerzy : ********************** Grzegorz : **************************************** Najmniej zarabia Janusz, a najwięcej Grzegorz. Na wykresie zastosowano automatyczne skalowanie, dlatego obok Janusza nie ma gwiazdek (minimum), natomiast obok Grzegorza wyświetla się 40 gwiazdek (maksimum). Świetnie ci idzie, Grzegorz! Ważniejsze w tym kodzie jest jednak to, że konwersja danych przebiegła bez problemu, bez konieczności zagłębiania się w szczegóły implementacji klasy Record. Wzorzec projektowy Adapter warto stosować zawsze wtedy, gdy występują dwa inter- fejsy API, które muszą ze sobą współpracować, a modyfikacja żadnego z tych interfej- sów nie wchodzi w rachubę. S P O S Ó B 73. Pisanie przenośnego kodu z wykorzystaniem wzorca Most Wykorzystanie wzorca Most w celu ukrycia szczegółów implementacji obiektów lub modyfikacji implementacji na podstawie środowiska. W jednej z firm, w której pracowałem, tworzyliśmy dużą aplikację w C++, która działała na wielu platformach. Podczas prac nad nią wielokrotnie wykorzystaliśmy wzorzec Most. Jego podstawową cechą jest możliwość ukrycia części implementacji klasy w innej klasie po to, by nie dopuścić do oglądania implementacji przez innych programistów lub dla- tego, że część implementacji zależy od platformy. 302 | Wzorce projektowe Pisanie przenośnego kodu z wykorzystaniem wzorca Most SPOSÓB 73. W przykładzie zaprezentowanym w niniejszym podrozdziale, w celu pokazania zalet wzorca Most, wykorzystamy przypadek, w którym część implementacji zależy od plat- formy. Na rysunku 7.7 pokazano związki pomiędzy klasami TableCreator i Table- CreatorImp. Rola pierwszej z nich polega na tworzeniu tabel w docelowej bazie da- nych. Klasę implementacyjną — TableCreatorImp — zdefiniowano w innym pliku, który jest włączany z katalogu specyficznego dla określonego typu bazy danych. Rysunek 7.7. Klasa TableCreator i jej klasa implementacyjna Dzięki takiej implementacji można stworzyć jedną wersję kodu specyficzną dla systemu Oracle i inną dla bazy MySQL (lub innej bazy danych). Jest to bardzo przydatne, zwłaszcza że w poszczególnych typach bazach danych występują różnice w składni kodu tworzącego tabele. Kod Kod pokazany na listingu 7.7 zapiszemy w pliku bridge.php. Listing 7.7. Klasa bazowa wzorca Most ?php require( sql.php ); class TableCreator { static function createTable( $name ) { TableCreatorImp::createTable( $name ); } } TableCreator::createTable( customer ); ? Kod pokazany na listingu 7.8 zapiszemy w pliku mysql/sql.php. Listing 7.8. Przykładowa klasa implementacyjna dla bazy danych MySQL ?php class TableCreatorImp { static public function createTable( $name ) { echo( Wersja klasy createTable dla bazy MySQL tworząca tabelę $name ); } } ? Wzorce projektowe | 303 SPOSÓB 73. Pisanie przenośnego kodu z wykorzystaniem wzorca Most Kod pokazany na listingu 7.9 zapiszemy w pliku oracle/sql.php. Listing 7.9. Przykładowa klasa implementacyjna dla bazy danych Oracle ?php class TableCreatorImp { static public function createTable( $name ) { echo( Wersja klasy createTable dla bazy Oracle tworząca tabelę $name ); } } ? Wykorzystanie sposobu Wykorzystanie zaprezentowanego sposobu wymaga zastosowania dodatkowych para- metrów w wierszu polecenia informujących interpreter PHP o tym, że w ścieżce plików włączanych ma się znaleźć katalog mysql lub oracle (co oznacza użycie mostu specyficz- nego dla określonego typu bazy danych). Oto wersja polecenia dla bazy danych MySQL: php -d include_path = .:/usr/local/php5/lib/php:mysql bridge.php Wersja klasy createTable dla bazy MySQL tworząca tabelę customer A oto wersja dla bazy danych Oracle: php -d include_path = .:/usr/local/php5/lib/php:oracle bridge.php Wersja klasy createTable dla bazy Oracle tworząca tabelę customer Nie jest to skomplikowany przepis na zrobienie rakiety, zatem zrozumienie idei przy- kładu nie powinno przysporzyć trudności. Klasa TableCreator została zaimplemen- towana przez jedną z kilku wersji klasy TableCreatorImp umieszczonych w katalo- gach specyficznych dla platformy. Oczywiście kod zamieszczony w przykładzie nie tworzy tabel. Jest to jedynie szkielet, w którym w praktycznej aplikacji trzeba by było wprowadzić odpowiedni kod. Arkana tworzenia tabel w różnych systemach baz danych nie są jednak istotne dla zrozumienia idei wzorca Most (można je zatem skwitować zdaniem „proszę zapoznać się z tym sa- modzielnie”). Jedną z poważnych wad wzorca Most jest brak możliwości rozszerzania implementacji określonych klas. W tym przypadku nie stanowi to problemu, ponieważ wszystkie me- tody klas implementacyjnych są statyczne. Jednak w przypadku obiektów zawierających metody niestatyczne klasa implementacyjna dziedziczy cechy klas nieimplementacyjnych. Na przykład klasa CButtonImp dziedziczy cechy po klasie CButton. W celu rozsze- rzenia implementacji trzeba by zastosować dziedziczenie po klasie CButtonImp, która jest ukryta. Problem ten dotyczy jednak w większym stopniu języków kompilowanych, takich jak C++. 304 | Wzorce projektowe Rozszerzalne przetwarzanie z wykorzystaniem wzorca Łańcuch odpowiedzialności SPOSÓB 74. S P O S Ó B 74. Rozszerzalne przetwarzanie z wykorzystaniem wzorca Łańcuch odpowiedzialności Wykorzystanie wzorca Łańcuch odpowiedzialności do utworzenia szkieletu kodu w trybie Plug and Play. Oglądanie futbolu z programistami jest zabawne. Nawet w czwartej kwarcie, kiedy wy- nik meczu wynosi 33:7, a pozostało zaledwie półtorej minuty do końca, w dalszym ciągu wskazują na wiele możliwości ostatecznego wyniku. Jest tak dlatego, że są przyzwycza- jeni do przewidywania wszystkich sytuacji niezależnie od tego, jak bardzo są niepraw- dopodobne (a właściwie zupełnie absurdalne). Przekonałem się, że większość pro- gramistów, włącznie ze mną, nie znosi zamykania drzwi odnośnie odpowiedzi na żadne z pytań. Lepiej napisać kod obsługujący 100 możliwych przypadków nawet wtedy, gdy nasz menedżer zaklina się, że jest tylko jedna możliwość. Dlatego właśnie wzorzec projektowy Łańcuch odpowiedzialności (ang. Chain of responsibility) jest tak ważny. Wyobraźmy sobie, że do pomieszczenia, w którym jest wiele osób, wcho- dzi sprzedawca ciastek, niosąc karton z pączkami o różnych smakach. Otwiera torebkę i wyjmuje pączek z marmoladą. Po kolei pyta poszczególne osoby, czy życzą sobie pączka z marmoladą, aż znajdzie się ktoś, kto będzie chciał. Następnie powtarza czynność dla pozostałych pączków z torebki do czasu, aż będzie pusta. To właśnie jest łańcuch odpowiedzialności. Każda osoba w pokoju rejestruje się wcze- śniej u dostawcy pączków. Kiedy przychodzi nowa partia pączków, dostawca widzi, kto je zamawiał, patrząc na listę zarejestrowanych osób. Zaleta tej sytuacji polega na tym, że dostawcy pączków nie interesuje, ile osób zamawia pączki, nie interesuje go nawet, co z nimi zrobią. Zajmuje się tylko zarządzaniem rejestracją i dostawami. W podrozdziale napiszę kod, w którym zamiast pączków będę posługiwał się adresami URL. Skrypt będzie dostarczał adresy URL do kilku procedur obsługi, które potencjalnie będą je przekierowywały. Jeśli żadna z procedur obsługi nie obsłuży adresu URL, taki adres będzie zignorowany. Na rysunku 7.8 pokazano, w jaki sposób ma działać ten system. Klasa URLMapper to dostawca pączków. Ma karton pełen adresów URL, które zamierza wręczyć obiektom o interfejsie URLHandler, które się po nie zgłoszą. W tym przypadku klasa ImageURL- Handler zarządza kierowaniem żądań adresów URL plików graficznych do skryptu obsługującego grafikę. W podobny sposób obiekt DocumentURLHandler przekiero- wuje żądania dokumentów do odpowiednich stron PHP. Dzięki temu aplikacja może przesłać adresy URL bez specjalnego kodu obsługi, a jednocześnie modyfikować je w miarę potrzeb. Kod Kod pokazany na listingu 7.10 zapiszemy w pliku chain.php. Wzorce projektowe | 305 SPOSÓB 74. Rozszerzalne przetwarzanie z wykorzystaniem wzorca Łańcuch odpowiedzialności Rysunek 7.8. Interfejs URLHandler, obiekt przekierowujący i dwa obiekty obsługujące adresy URL Listing 7.10. Przykład zastosowania w PHP wzorca projektowego Łańcuch odpowiedzialności ?php abstract class URLHandler { abstract function getRealURL( $url ); } class URLMapper { private $handlers = array(); private function URLMapper() { } public function addHandler( $handler ) { $this- handlers []= $handler; } public function mapURL( $url ) { foreach( $this- handlers as $h ) { $mapped = $h- getRealURL( $url ); if ( isset( $mapped ) ) return $mapped; } return $url; } public static function instance() { static $inst = null; if( !isset( $inst ) ) { $inst = new URLMapper(); } return $inst; } } class ImageURLHandler extends URLHandler { private $base; private $imgurl; public function ImageURLHandler( $base, $imgurl ) 306 | Wzorce projektowe Rozszerzalne przetwarzanie z wykorzystaniem wzorca Łańcuch odpowiedzialności SPOSÓB 74. { $this- base = $base; $this- imgurl = $imgurl; } public function getRealURL( $url ) { if ( preg_match( |^ .$this- base. (.*?)$| , $url, $matches ) ) { return $this- imgurl.$matches[1]; } return null; } } class DocumentURLHandler extends URLHandler { private $base; private $story_url; public function DocumentURLHandler( $base, $story_url ) { $this- base = $base; $this- story_url = $story_url; } public function getRealURL( $url ) { if ( preg_match( |^ .$this- base. (.*?)/(.*?)/(.*?)$| , $url, $matches ) ) { return $this- story_url.$matches[1].$matches[2].$matches[3]; } return null; } } $ih = new ImageURLHandler( http://mysite.com/images/ , http://mysite.com/image.php?img= ); URLMapper::instance()- addHandler( $ih ); $ih = new DocumentURLHandler( http://mysite.com/story/ , http://mysite.com/story.php?id= ); URLMapper::instance()- addHandler( $ih ); $testurls = array(); $testurls []= http://mysite.com/index.html ; $testurls []= http://mysite.com/images/dog ; $testurls []= http://mysite.com/story/11/05/05 ; $testurls []= http://mysite.com/images/cat ; $testurls []= http://mysite.com/image.php?img=lizard ; foreach( $testurls as $in ) { $out = URLMapper::instance()- mapURL( $in ); print $in -- $out ; } ? Wzorce projektowe | 307 SPOSÓB 74. Rozszerzalne przetwarzanie z wykorzystaniem wzorca Łańcuch odpowiedzialności Wykorzystanie sposobu Skrypt chain.php uruchomimy za pomocą interpretera PHP działającego w wierszu polecenia: php chain.php http://mysite.com/index.html -- http://mysite.com/index.html http://mysite.com/images/dog -- http://mysite.com/image.php?img=dog http://mysite.com/story/11/05/05 -- http://mysite.com/story.php?id=110505 http://mysite.com/images/cat -- http://mysite.com/image.php?img=cat http://mysite.com/image.php?img=lizard -- http://mysite.com/image.php?img=lizard Każdy wchodzący adres URL jest przesyłany poprzez obiekt URLMapper, który zwraca adres po jego przekształceniu. Pierwszy adres URL nie jest przekierowywany, zatem obiekt URLMapper przekazuje go w niezmienionej postaci. W drugim przypadku obiekt ImageURLHandler wykrywa, że adres URL dotyczy grafiki, zatem kieruje go do skryptu image.php. Trzeci adres został rozpoznany jako dokument, zatem skierowano go do skryptu story.php. Doskonałą własnością wzorca projektowego Łańcuch odpowiedzialności jest możliwość jego rozszerzania bez konieczności modyfikacji kodu aplikacji. Wystarczy, że obiekt dostaw- cy będzie wyposażony w dostatecznie rozbudowany interfejs API dla zarejestrowanych obiektów, aby obsłużyć niemal każdą sytuację. Jednym z najbardziej rozpoznawanych przykładów wzorca Łańcuch odpowiedzialności jest serwer WWW Apache, który działa jak jeden wielki dostawca pączków, delegując rożne żądania do zarejestrowanych procedur obsługi. Wzorzec Łańcuch odpowiedzialności nie zawsze jest łatwy do zastosowania. Jest z nim związanych kilka poważnych problemów. Trudno poprawia się w nim błędy i nie zawsze wiadomo, w jaki sposób należy go właściwie wykorzystywać. Występują dwie odmiany wzorca: jedna, w której w przypadku znalezienia procedury obsługi żądanie nie jest dalej przesyłane, i druga, gdzie przetwarzanie jest kontynuowane niezależnie od tego, czy znaleziono właściwą procedurę obsługi. Nie zawsze wiadomo, która z wersji jest wykorzystywana. Co więcej, drugi wariant, gdzie zdarzają się sytuacje wywołania wielu procedur obsługi, jest szczególnie trudny do diagnozowania. W przypadku wzorca Łańcuch odpowiedzialności potwierdza się reguła, że rozbudowane możliwości programów komputerowych osiąga się kosztem złożoności i wydajności. 308 | Wzorce projektowe Podział rozbudowanych klas na mniejsze z wykorzystaniem wzorca Kompozyt SPOSÓB 75. S P O S Ó B 75. Podział rozbudowanych klas na mniejsze z wykorzystaniem wzorca Kompozyt Wykorzystanie wzorca Kompozyt w celu podzielenia rozbudowanych klas na mniejsze. Kiedy słyszę informacje o wielkich bazach danych, w których są zapisane wszelkie in- formacje o osobach, których ktokolwiek i kiedykolwiek mógłby potrzebować, reaguję bardzo dziwnie. Większość osób myśli pewnie o prywatności, mnie przychodzi do głowy my
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

100 sposobów na PHP
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


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