Wzorce projektowe to sprawdzone rozwiązania często powtarzających się problemów w projektowaniu oprogramowania. Nie są to gotowe biblioteki ani fragmenty kodu do skopiowania – to szablony myślenia, które pomagają projektować elastyczny, testowalny i czytelny kod. W tej serii omówię najważniejsze wzorce z katalogu Gang of Four z przykładami w czystym PHP.
Skąd pochodzi pojęcie wzorców projektowych?
Termin „wzorzec projektowy” w kontekście oprogramowania spopularyzowała książka „Design Patterns: Elements of Reusable Object-Oriented Software” wydana w 1994 roku przez czterech autorów: Ericha Gamma, Richarda Helma, Ralpha Johnsona i Johna Vlissidesa. Od nazwisk autorów pochodzi skrót GoF – Gang of Four. Książka opisuje 23 wzorce podzielone na trzy kategorie.
Trzy kategorie wzorców GoF
Kreacyjne (Creational)
Dotyczą tworzenia obiektów. Ukrywają szczegóły instancjacji i dają elastyczność w tym co, jak i kiedy jest tworzone.
| Wzorzec | Problem który rozwiązuje |
|---|---|
| Factory Method | Podklasy decydują jaką klasę instancjonować |
| Abstract Factory | Tworzenie rodzin powiązanych obiektów bez znajomości konkretnych klas |
| Builder | Budowanie złożonych obiektów krok po kroku |
| Prototype | Klonowanie istniejących obiektów zamiast tworzenia od zera |
| Singleton | Gwarancja jednej instancji klasy w całej aplikacji |
Strukturalne (Structural)
Dotyczą kompozycji klas i obiektów. Pokazują jak składać obiekty w większe struktury zachowując ich elastyczność.
| Wzorzec | Problem który rozwiązuje |
|---|---|
| Adapter | Dopasowanie interfejsu klasy do oczekiwanego przez klienta |
| Bridge | Oddzielenie abstrakcji od implementacji |
| Composite | Traktowanie grupy obiektów jak jednego obiektu |
| Decorator | Dynamiczne dodawanie funkcjonalności bez dziedziczenia |
| Facade | Uproszczony interfejs do złożonego podsystemu |
| Flyweight | Współdzielenie stanu między wieloma obiektami dla oszczędności pamięci |
| Proxy | Pośrednik kontrolujący dostęp do innego obiektu |
Behawioralne (Behavioral)
Dotyczą algorytmów i przydziału odpowiedzialności między obiektami. Opisują jak obiekty komunikują się ze sobą.
| Wzorzec | Problem który rozwiązuje |
|---|---|
| Chain of Responsibility | Przekazywanie żądania przez łańcuch potencjalnych handlerów |
| Command | Enkapsulacja żądania jako obiekt z możliwością kolejkowania i cofania |
| Iterator | Sekwencyjny dostęp do elementów kolekcji bez znajomości jej struktury |
| Mediator | Centralizacja komunikacji między obiektami |
| Memento | Zapisywanie i przywracanie stanu obiektu |
| Observer | Powiadamianie wielu obiektów o zmianie stanu jednego |
| State | Zmiana zachowania obiektu w zależności od jego stanu wewnętrznego |
| Strategy | Wymienne algorytmy realizujące to samo zadanie |
| Template Method | Szkielet algorytmu z krokami definiowanymi przez podklasy |
| Visitor | Dodawanie operacji do obiektów bez zmiany ich klas |
Kiedy używać wzorców – i kiedy nie
Wzorce rozwiązują realne problemy – ale tylko wtedy gdy problem naprawdę istnieje. Kilka zasad które warto mieć w głowie:
Używaj wzorca gdy: widzisz konkretny problem który wzorzec rozwiązuje – trudność z rozszerzaniem kodu, silne sprzężenie między klasami, powtarzający się if-else decydujący „kto to obsłuży”, potrzeba wymienności implementacji.
Nie używaj wzorca gdy: kod jest prosty i nie rośnie. Dodanie wzorca do trzylinijkowej funkcji to over-engineering. Wzorce dodają warstwy abstrakcji – każda warstwa ma koszt w postaci złożoności kodu.
Antywzorzec „wzorzec dla wzorca”: dodawanie Factory tylko dlatego że „tak się robi”, nie dlatego że naprawdę potrzebujesz elastyczności w tworzeniu obiektów. Najlepsi developerzy znają wzorce, ale nie szukają okazji do ich zastosowania – wzorce pojawiają się naturalnie gdy kod ewoluuje.
Wzorce a zasady SOLID
Większość wzorców GoF to praktyczne realizacje zasad SOLID. Kilka przykładów:
- Strategy realizuje Open/Closed Principle – nowy algorytm to nowa klasa, nie modyfikacja istniejącej
- Observer realizuje Dependency Inversion – Subject nie zna konkretnych Observerów, tylko ich interfejs
- Factory Method realizuje Dependency Inversion – kod wysokiego poziomu nie tworzy konkretnych obiektów
- Decorator realizuje Open/Closed i Single Responsibility – dodajesz funkcjonalność bez modyfikacji oryginału
Plan serii
W kolejnych wpisach omówię najczęściej używane wzorce GoF z przykładami w czystym PHP:
- Kreacyjne: Factory Method i Abstract Factory, Singleton i Builder
- Strukturalne: Decorator i Proxy, Adapter i Facade
- Behawioralne: Observer i Strategy, Command i Chain of Responsibility
- Podsumowanie: które wzorce GoF są użyte w Magento 2 i gdzie je znaleźć
Każdy wpis zawiera implementację od zera, omówienie kiedy wzorzec ma sens i kiedy to over-engineering.
Podsumowanie
Wzorce GoF mają ponad 30 lat i nadal są aktualne – nie dlatego że są modne, ale dlatego że rozwiązują problemy które pojawiają się niezależnie od języka programowania i frameworka. PHP developer który rozumie wzorce czyta kod Magento 2, Symfony czy Laravela jak otwartą książkę – architektura tych frameworków jest dosłownie zbudowana z tych wzorców.
