Фабричный метод — это паттерн программирования, который используется для получения экземпляров объектов на основе некоторого заданного параметра. В своих PHP-проектах, я часто использую его. Но в других проектах, которые я вижу, многие фабричные классы весьма запутанны.
Пример
Допустим, у нас есть Фабрика, который будет создавать CarEngine на основе модели Car. Чаще всего я вижу такую реализацию:
class CarEngineFactory implements ICarEngineFactory
{
public function make(string $carBrand): IEngine
{
switch ($carBrand) {
case "mercedes":
return new MercedesEngine();
case "bmw":
return new BmwEngine();
default:
throw new CarEngineNotAvailableException();
}
}
}
Выглядит вроде нормально, да? Ну, пока у нас есть только два варианта, то да. Но если мы будем добавлять все больше и больше марок автомобилей в нашу систему, этот фабрикой станет всё сложнее пользоваться.
Проблемы:
- Параметры — это просто случайные строки, поэтому разработчикам будет сложно разобраться, что нужно передавать.
- Чем больше марок автомобилей добавлено — тем больше будет блок switch.
Я вижу решение этого таким:
class CarEngineFactory implements ICarEngineFactory
{
protected static $availableEngines = [
Mercedes::class => MercedesEngine::class,
Bmw::class => BmwEngine::class,
];
public function make(ICar $car): IEngine
{
$carClass = get_class($car);
if (!array_key_exists(get_class($car), self::$availableEngines)) {
throw new CarEngineNotAvailableException();
}
$engineClass = self::$availableEngines[$carClass];
return (new $engineClass());
}
}
Теперь у нас есть статический массив с классами Car и CarEngine. Вместо рандомных строк мы передаем весь объект. И теперь, если мы хотим добавить еще одну марку Car с соответствующим CarEngine, то нам просто нужно описать это в $availableEngines, и готово!
Если у нас очень большой блок switch case, то использование array_key_exists будет намного быстрее, потому что эта команда выполняет поиск по хешу и работает почти во временной сложности O(1) (почти — из-за возможных коллизий хешей).
Этот метод предоставляем нам больше гибкости. Например, $availableEngines можно переместить в конфигурационный файл.
Разумеется, это просто базовая реализация фабричного метода. Фабрики могут быть гораздо сложнее, но главное, что я хотел показать в этом примере, это то, что мы не должны передавать в них рандомные непонятные строки. Это затрудняет их чтение и использование другими разработчиками, работающими над этим же проектом.
Автор: Georgi Razsolkov
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.
