Порождающие шаблоны: Factory, Builder, Singleton
Управляйте созданием объектов с помощью порождающих шаблонов
«Порождающие шаблоны: Factory, Builder, Singleton» — бесплатный урок PHP Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения PHP Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс PHP Academy содержит 4 уроков всего.
Управление созданием
Порождающие паттерны отделяют то, что Вам нужно от способа создания. Если создание зависит от условий, состоит из нескольких шагов или должно быть централизовано, разрозненные вызовы new связывают вызывающий код с конкретными классами. Здесь рассматриваются фабрика, включая фабричный метод, строитель для сложной сборки и Singleton с присущими ему оговорками.
Простая фабрика
Простая фабрика централизует решение о создании за одним методом. Вызывающий код запрашивает логический тип и получает настроенный экземпляр конкретного класса, не зная имён классов.
<?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;
Фабричный метод
Паттерн фабричного метода откладывает создание экземпляра до подклассов. Базовый класс определяет алгоритм, вызывающий абстрактный create(); каждый подкласс выбирает конкретный продукт. Это соответствует OCP: новый создатель добавляется без изменения существующих.
<?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;
Абстрактная фабрика
Абстрактная фабрика создаёт семейства связанных объектов, которые должны использоваться вместе, например MySqlConnection и MySqlQueryBuilder. Она гарантирует совместимость частей, поскольку одна фабрика выдаёт весь набор. Используйте её, когда внутренняя согласованность семейства продуктов должна сохраняться.
Строитель: проблема
Когда объекту нужно много необязательных параметров, конструкторы превращаются в нечитаемые списки позиционных аргументов или цепочки перегруженных конструкторов, которых в PHP даже нет. Паттерн строителя собирает сложный объект шаг за шагом, возвращая в конце готовый корректный продукт.
Строитель с цепочками вызовов
Строитель с цепочками вызовов возвращает $this из каждого метода установки значения, а затем build() создаёт неизменяемый результат. Это оставляет сам продукт простым и переносит логику сборки в строитель.
<?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;
Строитель и именованные конструкторы
В более простых случаях именованные аргументы PHP 8 и именованные конструкторы, то есть статические фабричные методы, часто лучше полноценного строителя.
- Используйте именованные аргументы, когда все данные доступны сразу.
- Используйте строитель, когда сборка выполняется в несколько шагов, зависит от условий или повторно используется в разных местах вызова.
<?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 гарантирует наличие одного экземпляра и глобальной точки доступа к нему. Реализуйте его с помощью приватного конструктора и статического метода доступа. Он действительно полезен для объектов, которые обязаны быть уникальными в рамках процесса, но это также самый часто используемый неправильно паттерн.
<?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
Почему Singleton создаёт проблемы
Singleton вносит скрытое глобальное состояние: вызывающий код обращается к Config::instance(), вместо того чтобы объявить зависимость, что нарушает тестируемость и возможность параллельного выполнения. В современном PHP предпочитайте регистрировать один общий экземпляр в контейнере DI с жизненным циклом «единственный экземпляр» и внедрять его. Вы получаете один экземпляр без глобальной связанности.
Выбор подходящего инструмента
- Простая фабрика и фабричный метод: скрывают конкретные классы за решением о создании.
- Абстрактная фабрика: создаёт совместимые семейства продуктов.
- Строитель: собирает сложные объекты шаг за шагом.
- Singleton: крайняя мера; предпочитайте общие службы, управляемые контейнером.
Все четыре паттерна уменьшают связанность с конкретными конструкторами, благодаря чему код проще расширять и тестировать.
Фабрика на основе реестра
Более динамичная фабрика ищет создателей в реестре, поэтому новые типы регистрируют себя без изменения фабрики, что обеспечивает настоящее соответствие OCP. Так системы подключаемых модулей и сериализаторы во время выполнения сопоставляют имя типа с конструктором.
<?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
Быстрая проверка
Выберите наиболее подходящий порождающий инструмент для описанного сценария.
Итоги
Вы управляли созданием объектов с помощью порождающих паттернов: фабрики скрывают конкретные типы и выбирают семейства продуктов, строители пошагово и удобно собирают сложные объекты, а Singleton имеет свои компромиссы. Главный современный вывод: свободно используйте фабрики и строители, но заменяйте Singleton общим экземпляром в контейнере DI, чтобы зависимости оставались явными, а код — тестируемым.
Часто задаваемые вопросы
Урок «Порождающие шаблоны: Factory, Builder, Singleton» бесплатный?
Да — полный текст урока «Порождающие шаблоны: Factory, Builder, Singleton» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс PHP Academy, подпишись на CoddyKit PRO. Курс PHP Academy содержит 4 уроков всего.
Чему я научусь в уроке «Порождающие шаблоны: Factory, Builder, Singleton»?
Управляйте созданием объектов с помощью порождающих шаблонов Ты практикуешь PHP Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать PHP Academy?
Предыдущий опыт не требуется. PHP Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Порождающие шаблоны: Factory, Builder, Singleton»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке PHP Academy?
Да. Каждый урок PHP Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Принципы SOLID на практике
- Порождающие шаблоны: Factory, Builder, Singleton
- Структурные шаблоны: Adapter, Decorator, Facade
- Поведенческие шаблоны: Strategy, Observer, Command