продукт фабрики имеет особый метод

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

Интерфейс

interface Product
{
public function getName();
}

Товары

class ProductA implements Product{
public function getName()
{
return 'A';
}
}

class ProductB implements Product{
public function getName()
{
return 'B';
}
public function SpecialMethod()
{
return 'only B';
}
}

завод

class Factory(){
public function getProduct($type)
{
switch ($type) {
case 'A':
return new ProductA();
break;

case 'B':
return new ProductA();
break;

default:
# code...
break;
}
}
}

использование

function someBussinessLogic($type)
{

// ...ignore...

$factory = new Factory;
$product = $factory->getProduct($type);

if ($type == 'B') {
$product->SpecialMethod();
}

// ...ignore...
}

В использовании я должен проверить, если $type это б’. Я думаю, что это поведение довольно странно. Должен ли я просто сделать это или поставить SpecialMethod в interface Product? Или есть способ получше?


[редактировать]

Да, я беспокоюсь о том, что в будущем появятся продукты C, D, E … и у каждого есть свой особый метод. Если я просто добавлю все специальные методы в интерфейс, интерфейс станет очень большим, и все другие продукты должны будут реализовывать бессмысленные методы.

0

Решение

Я бы сделал это

$product = $factory->getProduct($type);

if (is_a($product, ProductB::class)) {
$product->SpecialMethod();
}

Или используйте интерфейс, если у вас будет много классов с SpecialMethodЗатем вы можете проверить интерфейс вместо одного класса.

Для справки это

Проверяет, принадлежит ли данный объект этому классу или имеет этот класс как один из его родителей.

Вы также можете использовать экземпляр

if ($product instanceof ProductB::class) {
$product->SpecialMethod();
}

Вот полезный пост о разнице между двумя

В чем разница между is_a и instanceof?

Также

Я тоже не вижу в этом ничего плохого

interface ProductInterface
{
public function getName();
public function SpecialMethod();
}

Однако я бы также добавил в него класс Abstract.

abstract class AbstractProduct impliments ProductInterface{
abstract public function getName();
public function SpecialMethod()
{
return ''; //or false
}
}

class ProductA extends AbstractProduct {
public function getName()
{
return 'A';
}
}

class ProductB extends AbstractProduct {
public function getName()
{
return 'A';
}
//override the concrete method in abstract class
public function SpecialMethod()
{
return 'only B';
}
}

Таким образом, вы можете просто оставить этот метод пустым в других классах, если вы не полагаетесь на SpecialMethod для некоторого типа возвращаемого значения. Я бы тоже изменил имя, как у меня, но это только мои предпочтения.

Тогда вы можете сделать это

$product = $factory->getProduct($type);
$product->SpecialMethod();  //return "only B" or ""

Потому что большинству классов будет свойственен пустой метод из абстрактного класса, и только те продукты, которые реализуют их переопределение, будут иметь значение. Это имеет смысл, если несколько продуктов будут иметь этот метод, но также имеет смысл создать отдельный интерфейс и проверить его. Так что это больше зависит от специфики того, что SpecialMethod на самом деле

0

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

Я бы сказал, что это зависит. Если вы планируете добавить этот метод к большему количеству классов со временем, перейдите к интерфейсу. Я бы не считал это плохой практикой, если бы были классы, которые все еще должны реализовывать этот метод, но с пустым телом. Таким образом, вы можете избавиться от своего if и не нужно возвращаться к своему коду, если класс C будет реализовывать этот метод тоже.

Если это будет ТОЛЬКО этот особый случай, я (лично) пошел бы на то, что, как вы уже сделали.


Или, может быть, вы можете вызвать специальный метод, где вы вызываете someBusinessLogic() поскольку после этого утверждения ничего не следует. С этим я имею в виду что-то вроде:

someBusinessLogic($type)->specialMethod();

Если этот подход работает для вашего существующего кода, я настоятельно рекомендую пойти по этому пути вместо if.

0

Заводская модель: Точность. В Википедии шаблон фабричного метода — это творческий паттерн, использующий фабричные методы для решения проблемы создания объектов без указания точного класса создаваемого объекта.
Здесь вы упомянули проблему с проверкой перед вызовом $ Продукт-> SpecialMethod ();

Если мы пройдем реализацию классов, то ясно, что ProductB только потребности specialMethod. Так что в someBussinessLogic ($ типа), независимо от того, как дизайн кода, практически вы хотите только вызвать specialMethod в случае TypeB, как нет specialMethod функциональность в других случаях (например, почему вы хотите позвонить specialMethod во всех случаях?). Таким образом, вы автоматически нуждаетесь в чеке.
С другой стороны, если вы пишете общий код, ваши сущности не должны иметь определенного поведения. И если они есть, вы должны подключить их из общего кода, а не ставить проверку внутри общего кода.

Теперь, когда вам придется явно обрабатывать такие проверки, вы можете задаться вопросом, как вам помогает фабричный шаблон ?. Итак, фабричный шаблон засияет в тот момент, когда вы захотите изменить функциональные возможности определенного типа, у вас будет одна точка, из которой вы могли бы подключить класс и подключить обновленный класс с новыми функциями.

Суть в том, что если вы хотите обрабатывать определенное поведение в своем общем коде, как в приведенном выше случае, вы будут нужно написать чек где-нибудь в вашем коде. Лучше быть вне универсальных модулей, чем ставить под угрозу целостность универсального кода.

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