Wzorce kreacyjne: Factory, Builder, Singleton
Proszę uporządkować tworzenie obiektów za pomocą wzorców kreacyjnych.
Wzorce kreacyjne: Factory, Builder, Singleton to bezpłatna lekcja PHP Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej PHP Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs PHP Academy zawiera 4 lekcji w sumie.
Kontrolowanie tworzenia
Wzorce kreacyjne oddzielają to, czego potrzebujesz, od sposobu, w jaki jest to budowane. Gdy tworzenie zależy od warunków, przebiega wieloetapowo lub musi być scentralizowane, rozproszenie new w bazie kodu uzależnia kod wywołujący od konkretnych klas. W tej części omówimy fabrykę (i metodę wytwórczą), budowniczego do złożonego składania obiektów oraz Singleton wraz z jego ograniczeniami.
Prosta fabryka
Prosta fabryka centralizuje decyzję dotyczącą tworzenia za pomocą jednej metody. Kod wywołujący prosi o typ logiczny i otrzymuje skonfigurowaną instancję konkretnej klasy, nie znając jej nazwy.
<?php
interface Notifier { public function send(string $msg): string; }
final class EmailNotifier implements Notifier {
public function send(string $m): string { return "email: $m"; }
}
final class SmsNotifier implements Notifier {
public function send(string $m): string { return "sms: $m"; }
}
final class NotifierFactory {
public static function make(string $channel): Notifier {
return match ($channel) {
'email' => new EmailNotifier(),
'sms' => new SmsNotifier(),
default => throw new InvalidArgumentException($channel),
};
}
}
echo NotifierFactory::make('sms')->send('Hi'), PHP_EOL;
Metoda wytwórcza
Wzorzec Metoda wytwórcza odracza tworzenie instancji do podklas. Klasa bazowa definiuje algorytm, który wywołuje abstrakcyjne create(); każda podklasa wybiera konkretny produkt. Jest to rozwiązanie zgodne z OCP: można dodać nowego twórcę bez modyfikowania istniejących.
<?php
abstract class ReportExporter {
abstract protected function create(): string;
public function export(): string {
return 'Exported as ' . $this->create();
}
}
final class PdfExporter extends ReportExporter {
protected function create(): string { return 'PDF'; }
}
final class CsvExporter extends ReportExporter {
protected function create(): string { return 'CSV'; }
}
echo (new PdfExporter())->export(), PHP_EOL;
echo (new CsvExporter())->export(), PHP_EOL;
Fabryka abstrakcyjna
Fabryka abstrakcyjna tworzy rodziny powiązanych obiektów, które muszą być używane razem (np. MySqlConnection + MySqlQueryBuilder). Gwarantuje zgodność elementów, ponieważ jedna fabryka dostarcza cały zestaw. Należy jej używać, gdy rodzina produktów musi pozostać wewnętrznie spójna.
Budowniczy: problem
Gdy obiekt wymaga wielu opcjonalnych parametrów, konstruktory przeradzają się w nieczytelne listy argumentów pozycyjnych albo w konstruktorów teleskopowych, których PHP nawet nie obsługuje. Wzorzec Budowniczy składa złożony obiekt krok po kroku, zwracając na końcu gotowy, poprawny produkt.
Budowniczy z płynnym interfejsem
Budowniczy z płynnym interfejsem zwraca $this z każdej metody ustawiającej, a następnie build() tworzy niezmienny wynik. Dzięki temu sam produkt pozostaje prosty, a logika składania zostaje przeniesiona do budowniczego.
<?php
final class Query {
public function __construct(public readonly string $sql) {}
}
final class QueryBuilder {
private string $table = '';
private array $where = [];
public function from(string $t): self { $this->table = $t; return $this; }
public function where(string $c): self { $this->where[] = $c; return $this; }
public function build(): Query {
$sql = "SELECT * FROM {$this->table}";
if ($this->where) { $sql .= ' WHERE ' . implode(' AND ', $this->where); }
return new Query($sql);
}
}
echo (new QueryBuilder())->from('users')->where('age > 18')->build()->sql, PHP_EOL;
Budowniczy a nazwane konstruktory
W prostszych przypadkach nazwane argumenty PHP 8 oraz nazwane konstruktory (statyczne metody fabrykujące) często sprawdzają się lepiej niż pełny budowniczy.
- Argumentów nazwanych należy używać, gdy wszystkie dane są dostępne jednocześnie.
- Budowniczego należy używać, gdy składanie przebiega wieloetapowo, zależy od warunków lub jest wykorzystywane w wielu miejscach wywołań.
<?php
final class Money {
private function __construct(public readonly int $cents, public readonly string $cur) {}
public static function fromDollars(float $d): self {
return new self((int) round($d * 100), 'USD');
}
public static function zero(string $cur = 'USD'): self {
return new self(0, $cur);
}
}
var_dump(Money::fromDollars(19.99)->cents); // int(1999)
Singleton
Singleton gwarantuje istnienie jednej instancji i zapewnia globalny punkt dostępu. Należy go zaimplementować za pomocą prywatnego konstruktora i statycznego akcesora. Jest naprawdę przydatny w przypadku elementów, które rzeczywiście muszą być unikatowe w obrębie procesu, ale jest również najbardziej nadużywanym wzorcem.
<?php
final class Config {
private static ?self $instance = null;
private array $data = ['debug' => true];
private function __construct() {}
public static function instance(): self {
return self::$instance ??= new self();
}
public function get(string $k): mixed { return $this->data[$k] ?? null; }
}
var_dump(Config::instance()->get('debug'));
var_dump(Config::instance() === Config::instance()); // true
Dlaczego Singleton szkodzi
Singletony wprowadzają ukryty stan globalny: kod wywołujący korzysta z Config::instance() zamiast deklarować zależność, co utrudnia testowanie i wykonywanie równoległe. We współczesnym PHP należy zamiast tego zarejestrować jedną współdzieloną instancję w kontenerze DI (cykl życia „pojedyncza instancja”) i wstrzykiwać ją. Otrzymuje się jedną instancję bez globalnego powiązania.
Wybór właściwego narzędzia
- Prosta fabryka/metoda wytwórcza: ukrywa konkretne klasy za decyzją dotyczącą tworzenia.
- Fabryka abstrakcyjna: tworzy zgodne ze sobą rodziny produktów.
- Budowniczy: składa złożone obiekty krok po kroku.
- Singleton: ostateczność; należy preferować współdzielone usługi zarządzane przez kontener.
Wszystkie cztery wzorce zmniejszają powiązanie z konkretnymi konstruktorami, dzięki czemu kod łatwiej rozszerzać i testować.
Fabryka oparta na rejestrze
Bardziej dynamiczna fabryka wyszukuje twórców w rejestrze, dzięki czemu nowe typy rejestrują się samodzielnie bez modyfikowania fabryki (prawdziwa zgodność z OCP). Tak działają systemy wtyczek i serializatory, które w czasie działania odwzorowują nazwę typu na konstruktor.
<?php
interface Shape { public function name(): string; }
final class Circle implements Shape { public function name(): string { return 'circle'; } }
final class Square implements Shape { public function name(): string { return 'square'; } }
final class ShapeRegistry {
private array $creators = [];
public function register(string $key, callable $factory): void {
$this->creators[$key] = $factory;
}
public function create(string $key): Shape {
return ($this->creators[$key] ?? throw new InvalidArgumentException($key))();
}
}
$r = new ShapeRegistry();
$r->register('circle', fn() => new Circle());
$r->register('square', fn() => new Square());
echo $r->create('square')->name(), PHP_EOL; // square
Szybki test
Należy wybrać najlepsze narzędzie kreacyjne dla danego scenariusza.
Podsumowanie
Kontrolowano tworzenie obiektów za pomocą wzorców kreacyjnych: fabryk do ukrywania konkretnych typów i wybierania rodzin produktów, budowniczych do płynnego składania złożonych obiektów oraz Singletona wraz z jego kompromisami. Współczesny wniosek jest następujący: fabryki i budowniczowie są dobrym wyborem, natomiast Singletona należy zastępować cyklem życia współdzielonej instancji w kontenerze DI, aby zachować jawne i testowalne zależności.
Często zadawane pytania
Czy lekcja „Wzorce kreacyjne: Factory, Builder, Singleton” jest bezpłatna?
Tak — pełny tekst „Wzorce kreacyjne: Factory, Builder, Singleton” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu PHP Academy, przejdź na CoddyKit PRO. Kurs PHP Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Wzorce kreacyjne: Factory, Builder, Singleton”?
Proszę uporządkować tworzenie obiektów za pomocą wzorców kreacyjnych. Ćwiczysz PHP Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć PHP Academy?
Nie wymagamy żadnego doświadczenia. PHP Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Wzorce kreacyjne: Factory, Builder, Singleton”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji PHP Academy?
Tak. Każda lekcja PHP Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Zasady SOLID w praktyce
- Wzorce kreacyjne: Factory, Builder, Singleton
- Wzorce strukturalne: Adapter, Decorator, Facade
- Wzorce behawioralne: Strategy, Observer, Command