Php 这是构造函数注入的合理实现吗?
继之后,我决定改用构造函数注入。请考虑以下代码:Php 这是构造函数注入的合理实现吗?,php,design-patterns,oop,dependency-injection,Php,Design Patterns,Oop,Dependency Injection,继之后,我决定改用构造函数注入。请考虑以下代码: <?php interface IAppServiceRegistry { public function getDb(); public function getLogger(); } interface IFooServiceRegistry extends IAppServiceRegistry { public function getFooBarBazMo
<?php
interface IAppServiceRegistry {
public function getDb();
public function getLogger();
}
interface IFooServiceRegistry extends IAppServiceRegistry {
public function getFooBarBazModel();
}
class AppServiceRegistry
implements IAppServiceRegistry, IFooServiceRegistry
{
private $logger;
private $db;
private $fooBarBazModel;
public function getDb() {
// return db (instantiate if first call)
}
public function getLogger() {
// return logger (instantiate if first call)
}
public function getFooBarBazModel() {
if (!isset($this->fooBarBazModel)) {
$this->fooBarBazModel = new FooBarBazModel( $this->getDb() );
}
return $this->fooBarBazModel;
}
}
// Example client classes:
/**
* Depends on db, logger and foomodel.
*/
class Foo {
private $db;
private $logger;
private $fooModel;
public function __construct(IFooServiceRegistry $services) {
$this->db = $services->getDb();
$this->logger = $services->getLogger();
$this->fooModel = $services->getFooModel();
}
}
/**
* Depends on only db and logger.
*/
class BarBaz {
private $db;
private $logger;
public function __construct(IAppServiceRegistry $services) {
$this->db = $services->getDb();
$this->logger = $services->getLogger();
}
}
虽然我通常不阅读php,但我认为我理解它的大部分内容。从技术上讲,它看起来不错,但你写
随着应用程序的发展,我将向注册表添加新的服务工厂方法
这往往会损害松耦合的概念,因为您现在使用的不是通用的服务定位器,而是专门的服务定位器
将这样的serivce注册表注入到每个类中都会违反(SRP),因为一旦一个类访问了注册表,就很容易请求比最初设想的还要多的依赖项,最终会导致一个错误
最好将所需的依赖项直接注入到需要它们的类中。因此,您的Foo类的构造函数应该采用db、logger和fooModel,而BarBaz类应该只采用db和logger参数
接下来的问题可能是:如果我需要很多不同的依赖项来执行工作,该怎么办?这需要一个真正丑陋的构造函数,它有很多参数,这与其他众所周知的OO实践背道而驰
是的,但是如果您需要很多依赖项,那么您可能违反了SRP,应该尝试将您的设计拆分为更细粒度的对象:)虽然我通常不阅读php,但我认为我理解其中的大部分内容。从技术上讲,它看起来不错,但你写
随着应用程序的发展,我将向注册表添加新的服务工厂方法
这往往会损害松耦合的概念,因为您现在使用的不是通用的服务定位器,而是专门的服务定位器
将这样的serivce注册表注入到每个类中都会违反(SRP),因为一旦一个类访问了注册表,就很容易请求比最初设想的还要多的依赖项,最终会导致一个错误
最好将所需的依赖项直接注入到需要它们的类中。因此,您的Foo类的构造函数应该采用db、logger和fooModel,而BarBaz类应该只采用db和logger参数
接下来的问题可能是:如果我需要很多不同的依赖项来执行工作,该怎么办?这需要一个真正丑陋的构造函数,它有很多参数,这与其他众所周知的OO实践背道而驰
是的,但是如果您需要很多依赖项,那么您可能违反了SRP,应该尝试将您的设计拆分为更细粒度的对象:)此实现与您之前向我们展示的服务定位器几乎相同
一个好问题是,在查看对象的类时,您是否了解完成其工作所需的关于对象的所有信息。对你来说,你还是不知道
如果Foo需要db、logger和model,您可以在构造函数中请求它们来明确这一点
关于这件事,这里有一个很好的解读:
此实现与您之前向我们展示的服务定位器几乎相同
一个好问题是,在查看对象的类时,您是否了解完成其工作所需的关于对象的所有信息。对你来说,你还是不知道
如果Foo需要db、logger和model,您可以在构造函数中请求它们来明确这一点
关于这件事,这里有一个很好的解读:
我最近一直在努力解决这类问题。服务定位器与依赖注入
我同意Mark的观点,即方法是根据需要将单个细粒度对象注入构造函数。正如Mark所强调的,唯一的缺点是,当您构建一个复杂的对象图时,不可避免地必须从某个地方开始。这意味着您的高级对象将有许多服务(对象)注入其中
解决这个问题的简单方法是用一些东西为你做艰苦的工作。谷歌的Guice就是一个很好的例子,在我看来,它是一种很好的处理事情的方式。遗憾的是,它是为Java编写的!有关于PHP的版本;在这一点上,我不确定他们中是否有人完全符合Guice的要求
我写了一篇更详细的文章;你可能会觉得有趣。它包括一个依赖注入框架的简单实现
底线是,如果您有一个类Foo,具有许多需求,那么您可以创建这样的类:
/**
* Depends on db, logger and foomodel.
*/
class Foo
{
private $db;
private $logger;
private $fooModel;
/**
* (other documentation here)
* @inject
*/
public function __construct(IDbService $db, ILoggerService $logger, $iModelService $model)
{
// do something
}
}
当您想要一个新的Foo对象时,只需请求依赖注入框架为您创建一个:
$foo = $serviceInjector->getInstance('Foo');
依赖项注入器将进行艰苦的工作,确保它注入依赖项。这包括依赖项的任何依赖项(如果有意义的话)。换言之,它将在树上递归地进行排序
稍后,当您发现需要一个IBarService对象时,您可以将其添加到Construtor中,而无需修改任何其他代码 我最近一直在努力解决这类问题。服务定位器与依赖注入
我同意Mark的观点,即方法是根据需要将单个细粒度对象注入构造函数。正如Mark所强调的,唯一的缺点是,当您构建一个复杂的对象图时,不可避免地必须从某个地方开始。这意味着您的高级对象将有许多服务(对象)注入其中
解决这个问题的简单方法是用一些东西为你做艰苦的工作。谷歌的Guice就是一个很好的例子,在我看来,它是一种很好的处理事情的方式。遗憾的是,它是为Java编写的!有关于PHP的版本;在这一点上,我不确定他们中是否有人完全符合Guice的要求
我写了一篇更详细的文章;你可能会觉得有趣。它包括一个依赖项的简单实现