Шаблоны проектирования на PHP

Одиночка (Singleton), порождающий

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


class Application
{
    private static $oInstance; // переменная для хренения экземпляра

    public static function getInstance(): self
    {
        if (!isset(static::$oInstance)) { // проверяем существование экземпляра (состояния)
            self::$oInstance = new self(); // если его не было, создаем его
        }

        return self::$oInstance; // возвращаем новое или имеющийся экземпляр
    }
}

var_dump(Application::getInstance()); // object(Application)#1 (0) {}
var_dump(Application::getInstance()); // object(Application)#1 (0) {}

Простая фабрика (Simple Factory), порождающий

Инкапсуляция создания объекта.


interface Animal // Интерфейс - все животные должны уметь говорить
{
    public function speak(); // издает звук
}

class Cat implements Animal // Кошка
{
    public function speak()
    {
        echo 'Мяу!';
    }
}

class Dog implements Animal // Собака
{
    public function speak()
    {
        echo 'Гав!';
    }
}

class AnimalFactory // Простая фабрика
{
    public function create($type) // Единственный метод - создает животных
    {
        if ($type === 'cat') {
            return new Cat();
        } elseif ($type === 'dog') {
            return new Dog();
        }
    }
}

// Использование
$factory = new AnimalFactory();
$cat = $factory->create('cat')->speak(); // Мяу!
$dog = $factory->create('dog')->speak(); // Гав!

Фасад (Facade), структурный

Предоставляет простой интерфейс к сложной системе классов.


class DatabaseBackup
{
    public function dumpDatabase(string $sDbName) {} // создание дампа бд
    public function compressDump() {} // сжатие дампа
}

class FileSystemBackup
{
    public function scanFiles(string $sDirectory) {} // листинг файлов
    public function archiveFiles(array $aFiles) {} // архивирование файлов
}

class CloudStorage
{
    public function upload(string $sFilename) {} // выгрузка файла
    public function checkSpace() {} // проверка места
}

class BackupLogger
{
    public function log(string $sMessage) {} // вывод лога
}

class BackupFacade
{
    private $oDbBackup;
    private $oFsBackup;
    private $oCloud;
    private $oLogger;

    public function __construct()
    {
        $this->oDbBackup = new DatabaseBackup();
        $this->oFsBackup = new FileSystemBackup();
        $this->oCloud = new CloudStorage();
        $this->oLogger = new BackupLogger();
    }

    // полная процедура всех видов бекапов
    public function createFullBackup(string $sProjectDir, string $sDbName) {}
}

// Использование
$oBackup = new BackupFacade();
$oBackup->createFullBackup("/var/www/project", "myapp_db");

Наблюдатель (Observer), поведенческий

Создание механизма подписки, позволяющий одним объектам следить и реагировать на события, происходящие в других объектах..


interface EventListener // интерфейс для всех слушателей событий
{
    public function handle($event); // класс-слушатель должен реализовать этот метод
}

class EventDispatcher // класс диспетчера событий
{
    private array $aListeners = []; // массив для хранения слушателей

    // метод для регистрации слушателя на определенное событие
    public function addListener($sEventName, EventListener $oListener)
    {
        $this->aListeners[$sEventName][] = $oListener;
    }

    public function dispatch($sEventName, $mData) // запуск событий
    {
        foreach ($this->aListeners[$sEventName] as $oListener) {
            $oListener->handle($mData);
        }
    }
}

class LoggerListener implements EventListener // слушатель для логирования событий
{
    public function handle($mEvent) {}
}

class EmailNotifierListener implements EventListener // слушатель для отправки email-уведомлений
{
    public function handle($mEvent) {}
}

// Использование
$oDispatcher = new EventDispatcher(); // Создаем экземпляр диспетчера событий
$oLogger = new LoggerListener(); // Слушатель для логирования
$oNotifier = new EmailNotifierListener(); // Слушатель для email-уведомлений

// Подписываем слушателей на событие 'user.registered'
$oDispatcher->addListener('user.registered', $oLogger);
$oDispatcher->addListener('user.registered', $oNotifier);

// Запускаем событие 'user.registered' с данными о пользователе
// Все подписанные слушатели получат эти данные
$oDispatcher->dispatch('user.registered', ['name' => 'Иван']);

Стратегия (Strategy), поведенческий

Определяет семейство схожих алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость.


interface IExportStrategy // Интерфейс стратегии экспорта данных.
{
    public function export(array $aData);
}

class CJsonExport implements IExportStrategy
{
    public function export(array $aData) {}  // Экспортирует данные в JSON формат.
}

class CXmlExport implements IExportStrategy
{
    public function export(array $aData) {} // Экспортирует данные в XML формат.
}

class CCsvExport implements IExportStrategy
{
    public function export(array $aData) {} //Экспортирует данные в CSV формат.
}

// Пример использования паттерна Стратегия
$aData = ['name' => 'John', 'age' => 30]; // a - array (массив данных)
$oExporter = new CJsonExport();            // o - object (объект экспортера)
echo $oExporter->export($aData);

Адаптер (Adapter), структурный

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


// Целевой интерфейс
interface INotification
{
    public function send(string $sMessage); // Отправляет уведомление
}

// Адаптируемые классы (разные сервисы)
class CEmailService
{
    public function sendEmail(string $sTo, string $sText) {} // Отправляет email
}

class CSmsService
{
    public function sendSms(string $sPhone, string $sMsg) {} // Отправляет SMS
}

// Адаптеры
class CEmailAdapter implements INotification
{
    public function __construct(private CEmailService $oEmailService) {}

    public function send(string $sMessage) // Адаптирует для email
    {
        return $this->oEmailService->sendEmail('user@test.com', $sMessage);
    }
}

class CSmsAdapter implements INotification
{
    public function __construct(private CSmsService $oSmsService) {}

    public function send(string $sMessage) // Адаптирует для SMS
    {
        return $this->oSmsService->sendSms('+1234567890', $sMessage);
    }
}

// Использование
$aNotifications = [
    new CEmailAdapter(new CEmailService()),
    new CSmsAdapter(new CSmsService())
];

foreach ($aNotifications as $oNotification) {
    $oNotification->send("Hello world!"); // теперь у обеих сервисов один метод
}

назад