这是一个与语言无关的问题,但我用PHP编写示例代码。
我们有两个班级:
UserRepository类处理与DB的交互并将所需的User加载到User对象并返回它。
在User类中,假设有一个首先没有加载的email属性,只要需要它就会从Database中延迟加载。 但用户类不应该知道 UserRepository 类,因此我们在此处创建一个电子邮件代理。哪个人知道 UserRepository ,并且需要收到电子邮件,它会从 UserRepository 中询问。
到目前为止,这是守则:
class User
{
private $username;
private $email_proxy;
public function __construct($username,EmailProxy $email_proxy)
{
$this->username = $username;
$this->email_proxy = $email_proxy;
}
public function get_username()
{
return $this->username;
}
public function get_email()
{
return $this->email_proxy->get_email($this->get_username());
}
}
class UserRepository
{
private $db;
public function __construct($db)
{
$this->db = $db;
}
/**
* @param string username
* @return string email , email address of the user
*/
public function get_email_by_username($username)
{
// interaction with DB, ...
return $user_email;
}
}
class EmailProxy
{
private $user_repository;
public function __construct(UserRepository $repository)
{
$this->user_repository = $repository;
}
public function get_email($username)
{
return $this->user_repository->get_email_by_username($username);
}
}
以下是使用示例:
$user_repository = new UserRepository($db_instance);
$email_proxy = new EmailProxy();
$user = new User('my_username', $email_proxy);
到目前为止一切顺利。 但这是我需要你帮助的棘手部分。 就其本质而言,UserRepository应负责从DataBase获取User对象,构造User对象并返回它。如下所示:
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
}
}
所以我的问题是如何将 EmailProxy 传递给由 UserRepository 创建的用户对象?
您是否将UserProxy实例注入UserRepository,以便将其注入新创建的User对象?
您是否会为此使用依赖注入容器?
您会使用工厂吗?
EmailProxy 已经知道 UserRepository ,如果我们将 EmailProxy 传递给 UserRepository ,它也会循环依赖。
任何代码/评论都将不胜感激。
谢谢,
答案 0 :(得分:1)
这是一个棘手的问题,我很想知道人们如何处理它。与此同时,这就是我对自己的看法。
我会在工厂
中创建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);
}
}
此类的目的是隐藏服务中的工厂。你只提供他们需要的东西。
现在你的UserRepository应该看起来像那样
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)
}
}
它看起来有点矫枉过正(并且它可能适用)但它允许您非常容易地重构代码,这对于长期应用是有益的。
我想这完全取决于您是喜欢易于阅读的代码还是易于(快速)编写的代码。
答案 1 :(得分:0)
可能是User
方法中UserRepository::get_email_by_username()
对象的引用。
类似的东西:
public function get_email_by_username(&$username)
{
// interaction with DB, ...
$username->setEmail($email_proxy);
}
http://php.net/manual/en/language.references.pass.php
在回复您的评论时,您只需在创建用户时调用UserRepository方法:
public function get_user_by_username($username)
{
$email_proxy = this->get_email_by_username($username);
return new User($fetched_username, $email_proxy);
}
然而,这似乎是一个非常明显的答案,我怀疑你问的是与发布的完全不同的东西。您可能想要重新提出您的问题:
所以我的问题是如何将EmailProxy传递给User对象 是由UserRepository创建的?