决定工厂中的 Class 到 Return
Deciding Which Class to Return in Factory
我正在创建一个 Product
摘要 class,它应该是
subclass根据产品类别分类(每个类别都有
不同的内部逻辑但相同的界面,因此我选择了
抽象模型)。但是,我希望用户调用工厂方法
它自动决定什么 subclass 到 return。首先是坏了吗
练习在抽象 class 本身中包含此工厂方法?
abstract class Product
{
abstract public function getDescription();
abstract public function getValue();
public static function
createProduct($category)
{
return # ...
}
}
我如何决定 class 到 return 的哪个子项?我当然可以做一个
switch-case
:
switch($category) {
case PROD_BOOK:
return new Book();
break;
case PROD_FOOD:
return new Food();
break;
}
但是这种硬编码 classes。添加新产品时,我会
必须为类别添加新常量并修改工厂
逻辑。我想保持工厂逻辑不变。有什么办法
将 table 类别键和 class 引用作为值?所以,我可以
做类似的事情:
return new ($classes[$category])();
然后我只需要在添加新的时候更新$classes
数组
产品。
看看 Zend Framework 工厂接口:
interface FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null);
}
其中 $container 具有调用其他注册实体的逻辑,requestedName 是从实体管理器请求实体时使用的名称,以及在需要自定义构建逻辑时使用的可选数组选项。
然后在 factory 内部你做一些类似的事情
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);
你应该有一个想法:)
如何实施的示例:
namespace Whatever;
use Any\Other\Book;
use Namespace\Food;
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];
}
}
这是一个已经回答过的旧线程,但是当我在寻找类似的东西时,我 post 我找到了解决方案:对于这样一个抽象的 class 工厂方法,也可以使用 get_called_class() 这将 return 调用 createProduct() 的子 class 的名称。
<?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);
使用这种方法,在抽象基础 class 中不需要子 classes 的映射。
我正在创建一个 Product
摘要 class,它应该是
subclass根据产品类别分类(每个类别都有
不同的内部逻辑但相同的界面,因此我选择了
抽象模型)。但是,我希望用户调用工厂方法
它自动决定什么 subclass 到 return。首先是坏了吗
练习在抽象 class 本身中包含此工厂方法?
abstract class Product
{
abstract public function getDescription();
abstract public function getValue();
public static function
createProduct($category)
{
return # ...
}
}
我如何决定 class 到 return 的哪个子项?我当然可以做一个
switch-case
:
switch($category) {
case PROD_BOOK:
return new Book();
break;
case PROD_FOOD:
return new Food();
break;
}
但是这种硬编码 classes。添加新产品时,我会 必须为类别添加新常量并修改工厂 逻辑。我想保持工厂逻辑不变。有什么办法 将 table 类别键和 class 引用作为值?所以,我可以 做类似的事情:
return new ($classes[$category])();
然后我只需要在添加新的时候更新$classes
数组
产品。
看看 Zend Framework 工厂接口:
interface FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null);
}
其中 $container 具有调用其他注册实体的逻辑,requestedName 是从实体管理器请求实体时使用的名称,以及在需要自定义构建逻辑时使用的可选数组选项。
然后在 factory 内部你做一些类似的事情
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);
你应该有一个想法:)
如何实施的示例:
namespace Whatever;
use Any\Other\Book;
use Namespace\Food;
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];
}
}
这是一个已经回答过的旧线程,但是当我在寻找类似的东西时,我 post 我找到了解决方案:对于这样一个抽象的 class 工厂方法,也可以使用 get_called_class() 这将 return 调用 createProduct() 的子 class 的名称。
<?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);
使用这种方法,在抽象基础 class 中不需要子 classes 的映射。