我正在创建一个Product
抽象类,它应该是根据产品类别进行子分类(每个类别都有不同的内部逻辑但相同的接口,因此我选择使用抽象模型(。 但是,我希望用户调用工厂方法它决定自动返回哪个子类。首先,不好吗将这个工厂方法包含在抽象类本身中的实践?
abstract class Product
{
abstract public function getDescription();
abstract public function getValue();
public static function
createProduct($category)
{
return # ...
}
}
如何决定返回哪个子类?我当然可以做一个 switch-case
:
switch($category) {
case PROD_BOOK:
return new Book();
break;
case PROD_FOOD:
return new Food();
break;
}
但是这种硬编码类。添加新产品时,我会必须为类别添加新常量并修改工厂逻辑。我想保持工厂逻辑完好无损。有什么办法可以将类别键和类引用表作为值?所以我可以执行以下操作:
return new ($classes[$category])();
然后我只需要在添加新数组时更新$classes
数组产品。
如何实现它的示例:
namespace Whatever;
use AnyOtherBook;
use NamespaceFood;
abstract class Product
{
protected static $categories = [
'book' => Book::class;
'food' => Food::class;
];
abstract public function getDescription();
abstract public function getValue();
public static function createProduct($category)
{
if (!isset(self::$categories[$category])) {
throw new InvalidArgumentException("There is no such thing as $category.");
}
return new self::$categories[$category];
}
}
看看 Zend Framework Factory Interface:
interface FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null);
}
如果$container具有调用其他已注册实体的逻辑,则 requestName 是从实体管理器请求实体时使用的名称,以及需要自定义生成逻辑时使用的可选数组选项。
然后从工厂内部做一些类似的事情
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
/** all parameters initialisation goes here **/
$result = new $requestedName(..$params);
return $result;
}
并通过以下方式获取对象实例
$myAwesomeFactory = new MyAwesomeFactory();
$book = $myAwesomeFactory($container, Book::class);
$food = $myAwesomeFactory($container, Food::class);
你应该有一个想法:)
这是一个已经很旧且已回答的线程,但是当我正在寻找类似的东西时,我发布了我找到的解决方案: 对于这样的抽象类工厂方法,还可以使用 get_called_class((,它将返回调用 createProduct(( 的子类的名称。
<?php
namespace Whatever;
abstract class Product
{
public static function createProduct() {
$class = get_called_class();
/** @var $inst Product */
$inst = new $class();
return $inst;
}
}
class Book extends Product
{
}
class Food extends Product
{
}
$product = Book::createProduct();
var_dump($product);
使用这种方法,不需要抽象基类中的子类映射。