API отражения в шаблоне Factory

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

Допустим, у нас есть 5 разных реализаций какого-то регистратора. Вот псевдокод, как это будет реализовано традиционным методом Factory:

class LoggerFactoryMethod extends AbstractFactoryMethod {
function makeLogger($param) {
$logger = NULL;
switch ($param) {
case "mysql":
$logger = new MysqlLogger;
break;
case "mongo":
$logger = new MongoLogger;
break;
case "txt":
$logger = new TxtLogger;
break;
case "redis":
$logger = new RedisLogger;
break;
case "memcached":
$logger = new MemcachedLogger;
break;
default:
$logger = new TxtLogger;
break;
}
return $logger;
}

Это прекрасно работает, но наличие множества условий if / else (или switch / code) не так уж круто. Допустим, завтра мы хотим добавить еще одну реализацию. Нам нужно будет изменить этот код и добавить новое условие регистра. При этом мы можем отделить принцип Open / Closed от принципов SOLID.

Вместо этого использование Reflection API более элегантно и не требует значительных изменений для новой реализации. Тот же пример с использованием Reflection API:

class LoggerFactoryMethod extends AbstractFactoryMethod {
function makeLogger($param) {
$allowed_implementations = array('mysql','mongo', 'txt', 'redis' , 'memcached');
$class = new ReflectionClass($param);

if (!in_array($param, $allowed_implementations) || !($class->IsInstantiable())){
return null;
}

return $class->newInstance();
}

Есть ли какие-либо недостатки в использовании Reflection API вместо традиционного шаблона Factory (при использовании условий if / else)? Это хорошая практика, чтобы использовать его?

0

Решение

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

Допустим, у вас есть файл конфигурации для хранения того, какую реализацию вы хотите использовать:

# path/to/config.php
<?php
return [
'mysql' => Some\Namespace\MysqlLogger::class,
'mongo'=> Some\Namespace\MongoLogger::class,
'txt' => Some\Namespace\TxtLogger::class,
'redis' => Some\Namespace\RedisLogger::class,
'memcached' => Some\Namespace\MemcachedLogger::class,
];

и ваша фабрика примет их и создаст регистратор на основе переданных и инициализированных параметров на основе конфигурации.

class LoggerFactoryMethod extends AbstractFactoryMethod {
protected $logger = [];
public function __construct()
{
$this->logger = require('path/to/config.php');
}

function makeLogger($param = 'txt') {
return new $this->logger[$param];
}

Позже, когда вам нужно добавить или удалить любой регистратор, вы можете просто добавить или удалить из списка в конфигурации.
Просто попробуйте реализовать LoggerInterface для каждого регистратора, чтобы ваша реализация не нарушала ваш код. Здесь есть стандартный интерфейс PSR для логгера: ПСР-3 Бревно следуя этому PSR-3 Log Описание

При этом я думаю, что это дает лучшую реализацию, чем оператор switch, и не требует дорогостоящих размышлений.

Просто мои два цента

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector