依赖注入回退可以吗?
Is it okay to have a dependency injection fallback?
我编写了一个使用 DI 的开源 PHP 库。
库为想要使用它的人提供了一个入口点,即 Client class,它有一个如下所示的构造函数(简化):
class Client {
protected $depOne;
protected $depTwo;
public function __construct(DependencyOne $depOne, DependencyTwo, $depTwo)
{
$this->depOne = $depOne;
$this->depTwo = $depTwo;
}
}
DependencyOne 和 DependencyTwo 也有自己的依赖项。这意味着任何想使用我的 没有使用 DI 的库的人都需要做这样的事情:
$dependencyThree = new DependencyThree();
$dependencyFour = new DependencyFour();
$dependencyFive = new DependencyFive();
$dependencyOne = new DependencyOne($dependencyThree, $dependencyFour);
$dependencyTwo = new DependencyTwo($dependencyFive);
$client = new Client($dependencyOne, $dependencyTwo);
$someStuff = $client->doTheThing();
让 的依赖注入只是这个 class 可选是不是很糟糕?例如
class Client {
protected $depOne;
protected $depTwo;
public function __construct(DependencyOne $depOne = null, DependencyTwo, $depTwo = null)
{
if (!isset($depOne)) {
$depThree = new DependencyThree();
$depFour = new DependencyFour();
$depOne = new DependencyOne($depThree, $depFour);
}
if (!isset($depTwo)) {
$depFive = new DependencyFive();
$depTwo = new DependencyTwo($depFive);
}
$this->depOne = $depOne;
$this->depTwo = $depTwo;
}
}
这意味着不使用 DI 的人可以这样做:
$client = new Client();
$someStuff = $client->doTheThing();
想要使用DI,或者为了单元测试目的,依赖还是可以传入的。
这是个坏主意吗?如果是,为什么?
我同意@Unex。使 DI 成为可选的并不坏,但我会在我的库中提供一个工厂,而不是在构造函数中硬配置。
通过这种方式,您可以保持与 DI 相同的松散耦合,并让 Client class 承担单一责任。为什么客户端 class 知道如何构造其他 classes? Class constructor 就是自知之明,仅此而已。请记住,构建一个完整的依赖链可能又大又复杂,也许您甚至必须阅读 bootstrap 中的配置文件、访问其他 php 模块中定义的常量、调用实用程序函数等;您不想将所有这些代码都放在构造函数中。
这正是我在开源项目中所做的,我认为这是一个非常好的解决方案。
它为用户提供了一种以 0 努力开始使用您的库的方法,同时让他们有可能覆盖任何内容。
我有时选择的另一种解决方案是 builder class or factory, see for example this constructor has mandatory parameter, but the ContainerBuilder
隐藏这种复杂性。
builder 的优势在于它将配置部分从 class 中取出。如果配置部分开始增长(关注点分离),这将很有用。
我编写了一个使用 DI 的开源 PHP 库。
库为想要使用它的人提供了一个入口点,即 Client class,它有一个如下所示的构造函数(简化):
class Client {
protected $depOne;
protected $depTwo;
public function __construct(DependencyOne $depOne, DependencyTwo, $depTwo)
{
$this->depOne = $depOne;
$this->depTwo = $depTwo;
}
}
DependencyOne 和 DependencyTwo 也有自己的依赖项。这意味着任何想使用我的 没有使用 DI 的库的人都需要做这样的事情:
$dependencyThree = new DependencyThree();
$dependencyFour = new DependencyFour();
$dependencyFive = new DependencyFive();
$dependencyOne = new DependencyOne($dependencyThree, $dependencyFour);
$dependencyTwo = new DependencyTwo($dependencyFive);
$client = new Client($dependencyOne, $dependencyTwo);
$someStuff = $client->doTheThing();
让 的依赖注入只是这个 class 可选是不是很糟糕?例如
class Client {
protected $depOne;
protected $depTwo;
public function __construct(DependencyOne $depOne = null, DependencyTwo, $depTwo = null)
{
if (!isset($depOne)) {
$depThree = new DependencyThree();
$depFour = new DependencyFour();
$depOne = new DependencyOne($depThree, $depFour);
}
if (!isset($depTwo)) {
$depFive = new DependencyFive();
$depTwo = new DependencyTwo($depFive);
}
$this->depOne = $depOne;
$this->depTwo = $depTwo;
}
}
这意味着不使用 DI 的人可以这样做:
$client = new Client();
$someStuff = $client->doTheThing();
想要使用DI,或者为了单元测试目的,依赖还是可以传入的。
这是个坏主意吗?如果是,为什么?
我同意@Unex。使 DI 成为可选的并不坏,但我会在我的库中提供一个工厂,而不是在构造函数中硬配置。 通过这种方式,您可以保持与 DI 相同的松散耦合,并让 Client class 承担单一责任。为什么客户端 class 知道如何构造其他 classes? Class constructor 就是自知之明,仅此而已。请记住,构建一个完整的依赖链可能又大又复杂,也许您甚至必须阅读 bootstrap 中的配置文件、访问其他 php 模块中定义的常量、调用实用程序函数等;您不想将所有这些代码都放在构造函数中。
这正是我在开源项目中所做的,我认为这是一个非常好的解决方案。
它为用户提供了一种以 0 努力开始使用您的库的方法,同时让他们有可能覆盖任何内容。
我有时选择的另一种解决方案是 builder class or factory, see for example this constructor has mandatory parameter, but the ContainerBuilder
隐藏这种复杂性。
builder 的优势在于它将配置部分从 class 中取出。如果配置部分开始增长(关注点分离),这将很有用。