我创建了一个这样的命令,但我想重构它以遵循 DI 原则:
public function handle()
{
$productChoice = $this->argument('product');
if ($productChoice == 1) {
$product = new ProductA();
} elseif ($productChoice == 2) {
$product = new ProductB();
} else {
$this->error('Invalid product choice. Use 1 for ProductA or 2 for ProductB.');
return;
}
if ($product instanceof ProductI) {
$this->info($product->details());
} else {
$this->error('The selected product does not implement the ProductI interface.');
}
}
如您所见,该命令依赖于productA和productB。我的问题是如何重构它。
这里有一些想法,但我不确定哪个更好或者是否有更好的方法:
1- 创建如下所示的工厂类并将其注入到命令类中
class ProductFactory
{
public function createProduct($productChoice)
{
switch ($productChoice) {
case 1:
return new ProductA();
case 2:
return new ProductB();
default:
return null;
}
}
}
2- 创建如下所示的服务提供者,并在类似
$product = $this->app->make("Product{$productChoice}")
的命令中使用它
public function register()
{
$this->app->bind('Product1', function () {
return new ProductA();
});
$this->app->bind('Product2', function () {
return new ProductB();
});
}
您需要的是从整数到类的映射。
在这种情况下,我更喜欢你建议的工厂保持干净和简单,但对创建方法进行一些小的修改:
public static function createFromId(int $productId): ProductI
{
return match ($productId) {
1 => new ProductA(),
2 => new ProductB(),
default => throw new InvalidArgumentException('No product with this id'),
};
}
ProductFactory::createFromId($productChoice)
。choice
重命名为 id
(因为选择不是产品本身的属性)。int
输入提示。ProductI
。match
声明而不是 switch
。null
,而是抛出异常。您还可以决定在 id 无效时返回实现
EmptyProduct
的 DefaultProduct
或 ProductI
。