Порождающие паттерны в PHP

·

3 min read

Порождающие (Creational) паттерны предназначены для управления созданием объектов. Они помогают сделать код более гибким, удобным для расширения и тестирования.


1. Singleton (Одиночка)

Гарантирует, что у класса есть только один экземпляр.

Все реализации одиночки сводятся к тому, чтобы скрыть конструктор по умолчанию и создать публичный статический метод, который и будет контролировать жизненный цикл объекта-одиночки.

Если у вас есть доступ к классу одиночки, значит, будет доступ и к этому статическому методу. Из какой точки кода вы бы его ни вызвали, он всегда будет отдавать один и тот же объект.

Пример

class Singleton {
    private static ?self $instance = null;

    private function __construct() {} // Закрытый конструктор
    private function __clone() {} // Запрещаем клонирование
    private function __wakeup() {} // Запрещаем десериализацию

    public static function getInstance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

// Использование
$instance1 = Singleton::getInstance();
$instance2 = Singleton::getInstance();
var_dump($instance1 === $instance2); // true

2. Factory Method (Фабричный метод)

Определяет интерфейс для создания объектов, но оставляет выбор типа создаваемого объекта подклассам.

Пример

interface Transport {
    public function deliver(): string;
}

class Truck implements Transport {
    public function deliver(): string {
        return "Delivery by truck";
    }
}

class Ship implements Transport {
    public function deliver(): string {
        return "Delivery by ship";
    }
}

abstract class Logistics {
    abstract public function createTransport(): Transport;

    public function planDelivery(): string {
        $transport = $this->createTransport();
        return $transport->deliver();
    }
}

class RoadLogistics extends Logistics {
    public function createTransport(): Transport {
        return new Truck();
    }
}

class SeaLogistics extends Logistics {
    public function createTransport(): Transport {
        return new Ship();
    }
}

// Использование
$logistics = new RoadLogistics();
echo $logistics->planDelivery(); // "Delivery by truck"

3. Abstract Factory (Абстрактная фабрика)

Позволяет создавать семейства взаимосвязанных объектов без указания их конкретных классов.

Пример

interface Button {
    public function render(): string;
}

class WindowsButton implements Button {
    public function render(): string {
        return "Windows Button";
    }
}

class MacButton implements Button {
    public function render(): string {
        return "Mac Button";
    }
}

interface GUIFactory {
    public function createButton(): Button;
}

class WindowsFactory implements GUIFactory {
    public function createButton(): Button {
        return new WindowsButton();
    }
}

class MacFactory implements GUIFactory {
    public function createButton(): Button {
        return new MacButton();
    }
}

// Использование
function renderGUI(GUIFactory $factory) {
    $button = $factory->createButton();
    echo $button->render();
}

$factory = new WindowsFactory();
renderGUI($factory); // "Windows Button"

4. Builder (Строитель)

Позволяет создавать сложные объекты поэтапно.

Пример

class House {
    public array $parts = [];

    public function show(): void {
        echo implode(", ", $this->parts) . "\n";
    }
}

interface Builder {
    public function buildWalls(): void;
    public function buildRoof(): void;
    public function getResult(): House;
}

class ConcreteHouseBuilder implements Builder {
    private House $house;

    public function __construct() {
        $this->house = new House();
    }

    public function buildWalls(): void {
        $this->house->parts[] = "Walls";
    }

    public function buildRoof(): void {
        $this->house->parts[] = "Roof";
    }

    public function getResult(): House {
        return $this->house;
    }
}

class Director {
    public function construct(Builder $builder): House {
        $builder->buildWalls();
        $builder->buildRoof();
        return $builder->getResult();
    }
}

// Использование
$builder = new ConcreteHouseBuilder();
$director = new Director();
$house = $director->construct($builder);
$house->show(); // "Walls, Roof"

5. Prototype (Прототип)

Позволяет копировать объекты вместо создания новых.

Пример

class Prototype {
    public string $name;
    public array $data;

    public function __construct(string $name, array $data) {
        $this->name = $name;
        $this->data = $data;
    }

    public function __clone() {
        $this->data = array_merge([], $this->data);
    }
}

// Использование
$original = new Prototype("Prototype 1", ["item1", "item2"]);
$clone = clone $original;
$clone->name = "Cloned Prototype";
$clone->data[] = "item3";

print_r($original); // ['name' => 'Prototype 1', 'data' => ['item1', 'item2']]
print_r($clone);    // ['name' => 'Cloned Prototype', 'data' => ['item1', 'item2', 'item3']]