Language agnostic 依赖注入、延迟加载、代理和循环依赖
这是一个与语言无关的问题,但我用PHP编写示例代码 我们有两个班:Language agnostic 依赖注入、延迟加载、代理和循环依赖,language-agnostic,dependency-injection,lazy-loading,factory,proxy-pattern,Language Agnostic,Dependency Injection,Lazy Loading,Factory,Proxy Pattern,这是一个与语言无关的问题,但我用PHP编写示例代码 我们有两个班: 用户类 用户存储库类 UserRepository类处理与DB的交互,并将所需的用户加载到用户对象中并返回它 在User类中,假设有一个email属性在第一时间并没有被加载,它将在需要时从数据库延迟加载。 但是User类不应该知道UserRepository类,所以我们在这里创建一个电子邮件代理。它知道用户存储库,当需要电子邮件时,它会从用户存储库中请求 以下是迄今为止的代码: 用户类 用户存储库类 电子邮件代理类 下面是使用示
$user_repository = new UserRepository($db_instance);
$email_proxy = new EmailProxy();
$user = new User('my_username', $email_proxy);
到目前为止还不错。
但这里有一个棘手的部分,我需要你的帮助。
从本质上讲,UserRepository应该负责从数据库中获取用户对象,构建用户对象并返回它。如下图所示:
class UserRepository
{
private $db;
public function __construct($db)
{
$this->db = $db;
}
public function get_email_by_username($username)
{
// interaction with DB, ...
return $user_email;
}
public function get_user_by_username($username)
{
// fetch the User from DB and ...
return new User($fetched_username) // missing the EmailProxy
}
}
因此,我的问题是如何将电子邮件代理传递给用户对象,该对象由用户存储库创建
- 是否将UserProxy实例注入UserRepository,以便将其注入新创建的用户对象
- 您会为此使用依赖项注入容器吗
- 你会使用工厂吗
谢谢,也许是对
UserRepository::get\u email\u by\u username()
方法中的User
对象的引用
比如:
public function get_email_by_username(&$username)
{
// interaction with DB, ...
$username->setEmail($email_proxy);
}
在回复您的评论时,您只需在创建用户时调用UserRepository方法:
public function get_user_by_username($username)
{
$email_proxy = this->get_email_by_username($username);
return new User($fetched_username, $email_proxy);
}
然而,这似乎是一个太明显的答案,我怀疑你问的问题与贴出的完全不同。您可能需要重新表述您的问题:
所以我的问题是如何将EmailProxy传递给
是由UserRepository创建的吗
这是一个棘手的问题,我想听听人们是如何处理的。同时,以下是我自己的想法 我将把
User
和UserRepository
类的创建放在工厂中
class ServiceFactory
{
private $instances=[];
public function createUser($data)
{
return new User($data)
->setEmailProxy($this->createEmailProxy());
}
public function createEmailProxy()
{
if (!isset($this->instances['EmailProxy'])) {
$this->instances['EmailProxy'] = new EmailProxy(
$this->createUserRepository()
);
}
return $this->instances['EmailProxy'];
}
public function createUserRepository()
{
if (!isset($this->instances['UserRepository'])) {
$this->instances['UserRepository'] = new UserRepository(
$db,
$this->createDtoFactory()
);
}
return $this->instances['UserRepository'];
}
public function createDtoProvider()
{
return new DtoProvider($this);
}
}
这是DtoProvider
类的代码
class DtoProvider
{
private $serviceFactory;
public function __construct($factory)
{
$this->serviceFactory = $factory;
}
public function createUser($data)
{
return $this->serviceFactory->createUser($data);
}
public function createOtherStuff($data)
{
return $this->serviceFactory->createOtherStuff($data);
}
}
此类的目的是对服务隐藏工厂。你只提供他们需要的东西
现在,您的用户存储库应该是这样的
class UserRepository
{
private $db;
private $services;
public function __construct($db, $serviceProvider)
{
$this->db = $db;
$this->services = $serviceProvider;
}
public function get_email_by_username($username)
{
// interaction with DB, ...
return $user_email;
}
public function get_user_by_username($username)
{
// fetch the User from DB and ...
return $this->services->createUser($data)
}
}
这似乎有点过火(很可能是),但它允许您非常容易地重构代码,这对长期应用程序是有好处的
我想这完全取决于您是喜欢易读的代码还是喜欢容易(快速)编写的代码。谢谢您的回复。但我的问题是UserRepository应该如何知道EmailProxy?因此,当它在“通过用户名获取用户”中创建新用户时,它可以传递它。“用户存储库->通过用户名获取电子邮件()”返回电子邮件字符串,而不是电子邮件代理。UserRepository无权访问“EmailProxy”。问题是EmailProxy知道UserRepository,因为它使用它来获取电子邮件。若我们也将EmailProxy实例传递给UserRepository,那个么它将是一个循环依赖项。谢谢你们的回复。它确实工作得很好,并且可以解耦依赖关系。正如你所说,这有点过分了。我想这取决于你是喜欢易读的代码还是喜欢容易(快速)编写的代码…:)
class ServiceFactory
{
private $instances=[];
public function createUser($data)
{
return new User($data)
->setEmailProxy($this->createEmailProxy());
}
public function createEmailProxy()
{
if (!isset($this->instances['EmailProxy'])) {
$this->instances['EmailProxy'] = new EmailProxy(
$this->createUserRepository()
);
}
return $this->instances['EmailProxy'];
}
public function createUserRepository()
{
if (!isset($this->instances['UserRepository'])) {
$this->instances['UserRepository'] = new UserRepository(
$db,
$this->createDtoFactory()
);
}
return $this->instances['UserRepository'];
}
public function createDtoProvider()
{
return new DtoProvider($this);
}
}
class DtoProvider
{
private $serviceFactory;
public function __construct($factory)
{
$this->serviceFactory = $factory;
}
public function createUser($data)
{
return $this->serviceFactory->createUser($data);
}
public function createOtherStuff($data)
{
return $this->serviceFactory->createOtherStuff($data);
}
}
class UserRepository
{
private $db;
private $services;
public function __construct($db, $serviceProvider)
{
$this->db = $db;
$this->services = $serviceProvider;
}
public function get_email_by_username($username)
{
// interaction with DB, ...
return $user_email;
}
public function get_user_by_username($username)
{
// fetch the User from DB and ...
return $this->services->createUser($data)
}
}