Как реализовать паттерн Factory?php-35

Паттерн Factory (Фабрика) — это порождающий шаблон проектирования, который предоставляет интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов.

Основные виды фабрик

1. Простая фабрика

<?php
interface PaymentMethod {
    public function pay(float $amount): bool;
}

class CreditCardPayment implements PaymentMethod {
    public function pay(float $amount): bool {
        echo "Paying $amount via Credit Card\n";
        return true;
    }
}

class PayPalPayment implements PaymentMethod {
    public function pay(float $amount): bool {
        echo "Paying $amount via PayPal\n";
        return true;
    }
}

class PaymentFactory {
    public static function create(string $type): PaymentMethod {
        return match ($type) {
            'credit' => new CreditCardPayment(),
            'paypal' => new PayPalPayment(),
            default => throw new InvalidArgumentException('Unknown payment type'),
        };
    }
}

// Использование
$payment = PaymentFactory::create('credit');
$payment->pay(100.00);

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

<?php
abstract class PaymentProcessor {
    abstract public function createPayment(): PaymentMethod;

    public function processPayment(float $amount): bool {
        $payment = $this->createPayment();
        return $payment->pay($amount);
    }
}

class CreditCardProcessor extends PaymentProcessor {
    public function createPayment(): PaymentMethod {
        return new CreditCardPayment();
    }
}

class PayPalProcessor extends PaymentProcessor {
    public function createPayment(): PaymentMethod {
        return new PayPalPayment();
    }
}

// Использование
$processor = new CreditCardProcessor();
$processor->processPayment(150.00);

3. Абстрактная фабрика

<?php
interface PaymentFactory {
    public function createPayment(): PaymentMethod;
    public function createValidator(): PaymentValidator;
}

class CreditCardFactory implements PaymentFactory {
    public function createPayment(): PaymentMethod {
        return new CreditCardPayment();
    }

    public function createValidator(): PaymentValidator {
        return new CreditCardValidator();
    }
}

class PayPalFactory implements PaymentFactory {
    public function createPayment(): PaymentMethod {
        return new PayPalPayment();
    }

    public function createValidator(): PaymentValidator {
        return new PayPalValidator();
    }
}

// Использование
$factory = new CreditCardFactory();
$payment = $factory->createPayment();
$validator = $factory->createValidator();

Преимущества паттерна Factory

  1. Инкапсуляция: Скрывает детали создания объектов
  2. Гибкость: Легко добавлять новые типы продуктов
  3. Тестируемость: Упрощает мокирование зависимостей
  4. Соблюдение SRP: Выносит создание объектов в отдельный компонент

Практический пример: подключение к БД

<?php
interface DatabaseConnection {
    public function connect(): PDO;
}

class MySQLConnection implements DatabaseConnection {
    public function connect(): PDO {
        return new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
    }
}

class PostgreSQLConnection implements DatabaseConnection {
    public function connect(): PDO {
        return new PDO('pgsql:host=localhost;dbname=test', 'user', 'pass');
    }
}

class DatabaseFactory {
    public static function create(string $type): DatabaseConnection {
        return match ($type) {
            'mysql' => new MySQLConnection(),
            'pgsql' => new PostgreSQLConnection(),
            default => throw new InvalidArgumentException('Unsupported database type'),
        };
    }
}

// Использование
$connection = DatabaseFactory::create('mysql');
$pdo = $connection->connect();

Сравнение типов фабрик

Критерий Простая фабрика Фабричный метод Абстрактная фабрика
Сложность Простая Средняя Сложная
Гибкость Ограниченная Высокая Очень высокая
Кол-во продуктов Один тип Один тип Группы связанных типов
Расширяемость Модификация фабрики Новые подклассы Новые фабрики

Лучшие практики реализации

  1. Используйте интерфейсы для продуктов
  2. Выносите параметры создания в конфигурацию
  3. Комбинируйте с Dependency Injection
  4. Применяйте для сложных объектов с множеством зависимостей

Резюмируем:

  • Простая фабрика — статический метод создания объектов
  • Фабричный метод — делегирует создание подклассам
  • Абстрактная фабрика — создает семейства связанных объектов
  • Уменьшает связанность кода и упрощает тестирование
  • Особенно полезен при работе с внешними сервисами и сложными зависимостями