Answer the question
In order to leave comments, you need to log in
How to instantiate a class in a factory method?
Пытаюсь реализовать паттерн "Простая фабрика" (в моем случае фабрика компонентов). Как принято создать экземпляр класса в фабричном методе: switch, reflection или?..
При использовании reflection фабричный метод (в примере ComponentFactory::createInstance
) будет возвращать тип object, а не интерфейс (ComponentInterface), что, кажется плохим.
switch выглядит неплохо за исключением одной проблемы. Допустим, завтра мы хотим добавить еще одну реализацию. Нам нужно будет изменить этот код и добавить новый case. В перспективе количество case в ComponentFactory::createInstance
может стать неприлично большим.
interface ComponentInterface
{
public function getName(): string;
}
class NewsComponent implements ComponentInterface
{
public function getName(): string
{
return 'news';
}
}
class ComponentFactory
{
public function createInstance($component): ?ComponentInterface
{
$instance = null;
switch ($component) {
case 'news':
$instance = new NewsComponent();
break;
}
return $instance;
}
public function createInstance($component)
{
if (!class_exists($component)) {
throw new ClassNotFoundException();
}
$reflectionClass = new ReflectionClass($component);
return $reflectionClass->newInstance();
}
}
// клиентский код
$componentFactory = new ComponentFactory();
$component = $componentFactory->createInstance('news');
Answer the question
In order to leave comments, you need to log in
1. case сам по себе не есть плохо, и это не считается дурным тоном. т.е. использовать конструкцию case можно и нужно.
2. Давайте подумает чем характеризуется объект экземпляра класса, а потом перейдем к фабрике.
Объект прежде всего характеризуется данными хранящимися внутри него. Т.е. Фабрика должна внутри себя хранить то что она выпускает (строит) и всю информацию о нем.
3. не используйте рефлекшен. это плохо это дурной код, без крайней необходимости не нужно. Обычно рефлекшены не используются в клиентском коде, только непосредственно в самих фреймворках. но раз вы задаете вопросы про фабрики, вы фреймворк не пишите, а значит и использование рефлекшенов вам не нужно.
4. Взгляните на оператор new (например, new Factory()) по сути оператор new и есть фабрика, которая из класса создает объект с уникальными (а может и не всегда) наборами данных.
5. в ссылке выше, вам дали информацию по рефакторингу switch но если прочитать там, написано,
не стоит трогать если
Зачастую оператор switch используется в фабричных паттернах проектирования (Фабричный метод, Абстрактная фабрика) для выбора создаваемого класса
/**
* Интерфейс Продукта объявляет операции, которые должны выполнять все
* конкретные продукты.
*/
interface Product
{
public function operation(): string;
}
/**
* Конкретные Продукты предоставляют различные реализации интерфейса Продукта.
*/
class ConcreteProduct1 implements Product
{
public function operation(): string
{
return "{Result of the ConcreteProduct1}";
}
}
class ConcreteProduct2 implements Product
{
public function operation(): string
{
return "{Result of the ConcreteProduct2}";
}
}
class Factory implements Product{
private $product;
function __construct(string $productClass){
switch($productClass){
case default:
case ConcreteProduct1::class:
$product = new ConcreteProduct1();
break;
case ConcreateProduct2::class:
$product = new ConcreateProduct2();
break;
}
$this->product = $product;
}
public function operation(): string
{
return $this->product->operation();
}
}
$product = new Factory(ConcreateProduct1::class);
echo $product->operation();
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question