决定在工厂返回哪个类



我正在创建一个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);

使用这种方法,不需要抽象基类中的子类映射。

最新更新