Фабричный метод — это паттерн программирования, который используется для получения экземпляров объектов на основе некоторого заданного параметра. В своих 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.