Wzorce projektowe: co to jest, rodzaje i przykłady
13 paź, 2026
Komentarze 0
Wzorce projektowe to nazwane, sprawdzone schematy rozwiązywania problemów, które powtarzają się przy projektowaniu kodu. Wzorzec opisuje, jak ułożyć klasy, obiekty albo funkcje, żeby dany problem przestał wracać. Sam kod piszesz za każdym razem od nowa, dopasowany do projektu. Klasyczny katalog 23 wzorców opisali w 1994 roku Erich Gamma, Richard Helm, Ralph Johnson i John Vlissides. To on do dziś wyznacza podział na trzy rodzaje: kreacyjne, strukturalne i behawioralne. W tym przewodniku wyjaśniamy ten podział, pokazujemy najczęściej używane wzorce z krótkimi przykładami w TypeScripcie i podpowiadamy, kiedy wzorzec bardziej szkodzi, niż pomaga. Osobny rozdział dotyczy kodu, który piszą asystenci AI.
Co to jest wzorzec projektowy
Wzorzec projektowy to opis problemu, który często pojawia się w kodzie, razem z ogólnym sposobem jego rozwiązania. Ma nazwę, kontekst, w którym działa, i znane koszty. Najważniejsza w praktyce jest nazwa. Gdy ktoś w przeglądzie kodu napisze “tu przyda się strategia”, cały zespół wie, o jaki układ chodzi, bez rysowania diagramu.
Pojęcie spopularyzowała książka “Design Patterns: Elements of Reusable Object-Oriented Software”, wydana przez Addison-Wesley 31 października 1994 roku. Jej autorów nazywa się Bandą Czworga (ang. Gang of Four, w skrócie GoF), stąd nazwa “wzorce GoF”. Wydawca opisuje ją jako katalog 23 wzorców z przykładami w C++ i Smalltalku. Po polsku książka ukazała się w wydawnictwie Helion jako “Wzorce projektowe. Elementy oprogramowania obiektowego wielokrotnego użytku”.
Warto pamiętać o dacie. Wzorce GoF powstały dla języków obiektowych z lat 90. W JavaScripcie, TypeScripcie czy Pythonie część z nich jest wbudowana w sam język albo sprowadza się do przekazania funkcji. Dlatego dobrze znać ich nazwy i cel, a implementację dopasować do języka, w którym piszesz.
Trzy rodzaje wzorców projektowych
Książka GoF dzieli 23 wzorce na trzy grupy według tego, jaki problem rozwiązują.
Rodzaj
Na jakie pytanie odpowiada
Wzorce w katalogu GoF
Kreacyjne (5)
jak tworzyć obiekty, żeby kod nie zależał od konkretnych klas
Fabryka abstrakcyjna, Budowniczy, Metoda wytwórcza, Prototyp, Singleton
Polskie nazwy nie są w pełni ujednolicone. W dokumentacji i ogłoszeniach o pracę często zostają angielskie: Builder, Proxy, Visitor. W rozmowie z zespołem używaj tej nazwy, którą zna reszta.
Najczęściej używane wzorce projektowe w jednym zdaniu
Nie trzeba znać wszystkich 23 wzorców, żeby czytać cudzy kod. Poniższa lista obejmuje te, które spotkasz najczęściej w aplikacjach webowych i bibliotekach.
Wzorzec
Rodzaj
Po co jest
Singleton
kreacyjny
jedna, wspólna instancja obiektu w całej aplikacji, na przykład konfiguracji
Fabryka (prosta fabryka i Metoda wytwórcza)
kreacyjny
tworzy właściwy obiekt, a reszta kodu nie zna konkretnych klas
Budowniczy (Builder)
kreacyjny
składa skomplikowany obiekt krok po kroku zamiast przez konstruktor z dziesięcioma argumentami
Adapter
strukturalny
dopasowuje interfejs obcej biblioteki albo starego kodu do interfejsu, którego oczekuje aplikacja
Fasada
strukturalny
daje jeden prosty punkt wejścia do skomplikowanego podsystemu
Dekorator
strukturalny
dokłada zachowanie do obiektu albo funkcji bez zmiany jej kodu
Pełnomocnik (Proxy)
strukturalny
stoi przed obiektem i kontroluje dostęp do niego, na przykład buforuje albo sprawdza uprawnienia
Obserwator
behawioralny
powiadamia wielu odbiorców, gdy coś się zmieni
Strategia
behawioralny
pozwala podmienić algorytm bez zmiany kodu, który go używa
Polecenie
behawioralny
zamienia operację w obiekt, który da się zapisać, kolejkować albo cofnąć
Stan
behawioralny
zmienia zachowanie obiektu zależnie od jego stanu bez rozbudowanego switch
Iterator
behawioralny
przechodzi po elementach zbioru bez ujawniania, jak zbiór jest zbudowany
Frontend Master 2026 · Kodożercy
Frontend dla osób, które chcą pisać kod, nie tylko prompty
Frontend Master 2026 to pakiet, który daje Ci fundamenty potrzebne w pierwszej pracy frontendowej. HTML, CSS, JavaScript, Git – polskie wideo, projekty, ścieżka od początku do deploy.
Przykłady są celowo krótkie i dotyczą jednego wymyślonego sklepu internetowego: konfiguracji, powiadomień, płatności, kosztu dostawy i koszyka. Klasyczne implementacje w czystym JavaScripcie, w tym fabrykę pojazdów, fasadę i mediator, opisujemy w osobnym tekście o wzorcach projektowych w JavaScript.
Singleton: moduł jako najprostsza wersja
W JavaScripcie i TypeScripcie najprostszym singletonem jest moduł. Według dokumentacji MDN moduł wykonuje się tylko raz, nawet gdy importuje go wiele plików, a jego zmienne nie trafiają do zakresu globalnego.
// config.ts - każdy import dostaje ten sam obiekt
export const config = {
apiUrl: "https://api.sklep.example",
currency: "PLN",
};
Klasa z prywatnym konstruktorem i metodą getInstance() daje ten sam efekt, ale w tych językach rzadko jest potrzebna.
Prosta fabryka: powiadomienia różnymi kanałami
Kod zamówienia chce wysłać powiadomienie i nie powinien wiedzieć, czy idzie ono mailem, czy SMS-em.
Nowy kanał wymaga nowej klasy oraz rozszerzenia typu i logiki fabryki. Kod zamówienia się nie zmienia.
To jest prosta fabryka: jedna funkcja wybiera klasę na podstawie parametru. W katalogu GoF jej nie ma. Jej klasycznym krewnym jest Metoda wytwórcza, w której klasa bazowa deklaruje metodę tworzącą obiekt, a klasy potomne ją nadpisują i same decydują, co powstanie. W codziennym kodzie aplikacji webowych częściej spotkasz prostą fabrykę.
Adapter: obca bramka płatności
Sklep ma własny interfejs płatności, a dostawca daje bibliotekę z innymi nazwami metod i kwotą w groszach. Adapter tłumaczy jedno na drugie.
interface PaymentGateway {
charge(amountPln: number): Promise<string>;
}
// biblioteka dostawcy, której nie zmieniamy
declare class VendorPayClient {
createTransaction(opts: { amountGrosze: number }): Promise<{ id: string }>;
}
class VendorPayAdapter implements PaymentGateway {
constructor(private client: VendorPayClient) {}
async charge(amountPln: number) {
const tx = await this.client.createTransaction({
amountGrosze: Math.round(amountPln * 100),
});
return tx.id;
}
}
Zmiana dostawcy oznacza napisanie nowego adaptera. Reszta aplikacji dalej woła charge().
Strategia: koszt dostawy
Koszt dostawy liczy się inaczej dla kuriera, paczkomatu i odbioru osobistego. Każdy sposób jest osobną funkcją z tym samym podpisem, więc znika rozbudowany if.
W JavaScripcie strategię spotykasz codziennie. Funkcja porównująca przekazywana do Array.prototype.sort() to właśnie wymienny algorytm.
Obserwator: koszyk, który informuje o zmianach
W przeglądarce obserwator jest wbudowany. Interfejs EventTarget ma konstruktor i metody addEventListener(), removeEventListener() oraz dispatchEvent(), więc własna klasa może po nim dziedziczyć.
Licznik w nagłówku, podsumowanie zamówienia i analityka mogą nasłuchiwać tego samego zdarzenia, a koszyk nic o nich nie wie.
Kiedy wzorzec projektowy szkodzi
Wzorzec ma koszt: dodatkowe pliki, interfejsy i warstwy, przez które trzeba przejść, żeby zrozumieć, co robi kod. Opłaca się, gdy problem, który rozwiązuje, naprawdę występuje. Interfejs z jedną implementacją i fabryką, która zawsze zwraca ten sam obiekt, tylko utrudnia czytanie. Rozsądna kolejność to najpierw prosty kod, a wzorzec dopiero przy drugim albo trzecim podobnym przypadku.
Najczęściej krytykowany jest Singleton. Działa jak zmienna globalna, więc testy wpływają na siebie nawzajem, a zależność od niego nie jest widoczna w podpisie funkcji. Bezpieczniej przekazać konfigurację jako parametr albo przez konstruktor. Druga pułapka to głębokie hierarchie dziedziczenia. Sami autorzy książki GoF zalecają we wstępie przedkładać kompozycję obiektów nad dziedziczenie klas. Więcej o zasadach, które stoją za tymi decyzjami, piszemy w tekście o zasadach SOLID i DRY.
Wzorce z katalogu GoF działają na poziomie klas i funkcji. Decyzje o podziale całej aplikacji na warstwy, usługi czy frontend i backend to już architektura, opisana w przewodniku po architekturze aplikacji webowych.
Wzorce projektowe w kodzie pisanym przez AI
Asystenci AI rozpoznają nazwy popularnych wzorców i potrafią generować ich typowe implementacje. Da się to wykorzystać w obie strony.
Przy pisaniu polecenia nazwa wzorca jest krótszym i dokładniejszym opisem niż akapit tekstu. Prośba “dodaj obsługę nowej bramki płatności jako adapter do interfejsu PaymentGateway” zostawia modelowi mniej miejsca na zgadywanie niż “dodaj nową płatność”.
Przy przeglądzie kodu od AI warto zadać trzy pytania:
Czy każdy nowy interfejs ma więcej niż jedną implementację albo realny powód, żeby ją mieć?
Czy wzorzec rozwiązuje problem opisany w zadaniu?
Da się to samo napisać funkcją, którą język już ma, na przykład zdarzeniem albo funkcją przekazaną jako parametr?
Jeśli odpowiedź na pierwsze dwa pytania brzmi “nie”, poproś model o uproszczenie albo uprość sam. Znajomość wzorców przydaje się wtedy bardziej niż przy pisaniu od zera, bo pozwala szybko rozpoznać, co w wygenerowanym kodzie jest potrzebne. O tym, jak kod z asystentów zachowuje się po wdrożeniu, piszemy w tekście o vibe codingu w produkcji.
FAQ
Ile jest wzorców projektowych?
Klasyczny katalog z książki Gammy, Helma, Johnsona i Vlissidesa z 1994 roku ma 23 wzorce: 5 kreacyjnych, 7 strukturalnych i 11 behawioralnych. Później opisano wiele innych, na przykład wzorce architektoniczne, wzorce współbieżności czy wzorce integracji systemów, ale gdy ktoś mówi o “wzorcach projektowych”, zwykle ma na myśli tę dwudziestkę trójkę.
Od których wzorców zacząć naukę?
Od tych, które spotkasz w kodzie najszybciej: Strategii, Obserwatora, Adaptera, Fasady, fabryki i Singletona. Łatwo je rozpoznać we frameworkach i bibliotekach, a ich przykłady mieszczą się w kilkunastu linijkach.
Czym różni się wzorzec projektowy od wzorca architektonicznego?
Wzorzec projektowy dotyczy kilku klas albo funkcji, na przykład tego, jak podmienić algorytm liczenia dostawy. Wzorzec architektoniczny, taki jak MVC, opisuje podział całej aplikacji na duże części i ich komunikację.
Czy wzorce projektowe mają sens w JavaScripcie i Pythonie?
Tak, choć wyglądają inaczej niż w C++ i Smalltalku, w których zapisano przykłady w książce GoF. Funkcje przekazywane jako argumenty zastępują wiele klas z Polecenia i Strategii, moduły pełnią rolę Singletona, a iteratory i zdarzenia są częścią języka albo platformy.
{ aplikacje webowe }
Masz pomysł na aplikację? Najpierw go zobacz
Zanim zainwestujesz w pełny system, przygotujemy klikalny prototyp, który pokażesz zespołowi albo klientom. Potem budujemy aplikację webową, która rośnie razem z firmą.
Wzorce projektowe to nazwane schematy rozwiązań powtarzalnych problemów w kodzie. Klasyczny katalog 23 wzorców z 1994 roku dzieli je na kreacyjne, strukturalne i behawioralne. Najczęściej spotkasz Singleton, fabrykę, Adapter, Fasadę, Dekorator, Obserwatora i Strategię. W JavaScripcie i TypeScripcie wiele z nich realizują same mechanizmy języka: moduł działa jak singleton, EventTarget daje obserwatora, a przekazana funkcja jest strategią. Wzorzec opłaca się wtedy, gdy problem naprawdę się powtarza. Przy jednym przypadku dokłada tylko warstw. W pracy z asystentami AI nazwy wzorców skracają polecenia, a ich znajomość pomaga odsiać z wygenerowanego kodu abstrakcje, których zadanie nie wymagało.
Newsletter · DevstockAcademy & Kodożercy
Bądź na bieżąco ze światem IT, AI i automatyzacji
Co wtorek: newsy z branży, praktyczne tipy i narzędzia które warto znać. Zero spamu.
Specjalista SEO i content marketingu w Devstock. Zajmuję się strategią treści, automatyzacją procesów marketingowych i wdrożeniami AI w codziennej pracy. Badam nowe narzędzia, adaptuję je do realnych zadań i piszę o tym, co faktycznie działa.