第二季度:
如果您在您的 $registry 对象中到处传递......那么您的 Registry 并不是真正的 Registry(正如 Fowler 所描述的那样)。 p>
Registry 或多或少是一个具有 get/set 方法的全局对象(“众所周知”)。
在 PHP 中,实现 Registry 的两个常见原型是
单身
class RegistryAsSingleton
{
public static function getInstance (){
//the singleton part
}
public function getStuff ()
{
//some stuff accessed thanks to the registry
}
}
到处都是静态方法
class RegistryAsStatic
{
public static function getStuff()
{
}
}
到处传递你的Registry使它,好吧,只是一个对象:一个没有比提供对其他对象的引用更大的目的的容器。
您的 DI 容器(使用您在 OP 中建议的 Pimple)本身就是一种注册表:它是众所周知的,使您能够从任何地方获取组件。
所以是的,我们可以说您的 DI 容器将通过执行相同的功能来消除注册表的要求和必要性。
但是(总有一个但是)
注册表总是有罪的,直到
被证明是无辜的
(马丁·福勒)
如果您使用 DI 容器 来替换您的 Registry,这可能是错误的。
例如:
//probably a Wrong usage of Registry
class NeedsRegistry
{
public function asAParameter(Registry $pRegistry)
{
//Wrong dependency on registry where dependency is on Connection
$ct = $pRegistry->getConnection();
}
public function asDirectAccess ()
{
//same mistake, more obvious as we can't use another component
$ct = Registry::getInstance()->getConnection();
}
}
//probably a wrong replacement for Registry using DI Container
class NeedsContainer
{
public function asAParameter(Container $pRegistry)
{
//We are dependent to the container with no needs,
//this code should be dependent on Connection
$ct = $pContainer->getConnection();
}
public function asDirectAccess ()
{
//should not be dependent on container
$ct = Container::getInstance()->getConnection();
}
}
为什么会这样?因为你的代码依赖程度不亚于以前,它仍然依赖于一个没有提供明确目标的组件(注册表或容器)(我们可以在这里想到接口)
注册表模式在某些情况下很有用,因为它是一种定义组件或数据(例如全局配置)的简单且相当便宜的方法。
通过删除依赖项来重构上述示例而不依赖 DI 的方法是:
class WasNeedingARegistry
{
public function asAParameter (Connection $pConnection)
{
$pConnection->doStuff();//The real dependency here, we don't care for
//a global registry
}
}
//the client code would be like
$wasNeedingARegistry = new WasNeedingARegistry();
$wasNeedingARegistry->setConnection($connection);
当然,如果客户端代码不知道连接,这可能是不可能的,这可能是您可能首先结束使用注册表的原因。
现在 DI 开始发挥作用
使用 DI 让我们的生活变得更美好,因为它会处理依赖项并使我们能够以随时可用的状态访问依赖项。
您将在代码中的某处配置组件:
$container['connection'] = function ($container) {
return new Connection('configuration');
};
$container['neededARegistry'] = function ($container) {
$neededARegistry = new NeededARegistry();
$neededARegistry->setConnection($container['connection']);
return $neededARegistry;
};
现在您拥有重构代码所需的一切:
// probably a better design pattern for using a Registry
class NeededARegistry
{
public function setConnection(Connection $pConnection)
{
$this->connection = $pConnection;
return $this;
}
public function previouslyAsDirectAccess ()
{
$this->connection->doStuff();
}
}
//and the client code just needs to know about the DI container
$container['neededARegistry']->previouslyAsDirectAccess();
“客户端”代码应尽可能隔离。客户端应该负责并注入自己的依赖项(通过set- 方法)。客户端不应该负责处理其依赖项的依赖项。
class WrongClientCode
{
private $connection;
public function setConnection(Connection $pConnection)
{
$this->connection = $pConnection;
}
public function callService ()
{
//for the demo we use a factory here
ServiceFactory::create('SomeId')
->setConnection($this->connection)
->call();
//here, connection was propagated on the solely
// purpose of being passed to the Service
}
}
class GoodClientCode
{
private $service;
public function setService(Service $pService)
{
//the only dependency is on Service, no more connection
$this->service = $pService;
}
public function callService ()
{
$this->service->setConnection($this->connection)
->call();
}
}
DI 容器将使用已正确配置其 Connection 的 Service 配置 GoodClientCode
至于 Singleton 方面,是的,它可以让你摆脱它们。
希望这会有所帮助