3

这是一个独立于语言的问题,但我用 PHP 编写示例代码。

我们有两个类:

  1. 用户
  2. UserRepository

UserRepository 类处理与 DB 的交互并将所需的 User 加载到 User 对象中并返回它。

在 User 类中,假设有一个 email 属性一开始就没有加载,它会在需要时从数据库中延迟加载。但是User类不应该知道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());
    }
}

UserRepository 类

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创建的User对象?

  • 您是否将 UserProxy 实例注入到 UserRepository 以便可以将其注入到新创建的 User 对象中?

  • 你会为此使用依赖注入容器吗?

  • 你会用工厂吗?

编辑

EmailProxy已经知道UserRepository,如果我们也将EmailProxy传递给UserRepository,那将是一个循环依赖。

任何代码/评论将不胜感激。

谢谢,

4

2 回答 2

1

这是一个棘手的问题,我很想听听人们如何处理它。与此同时,这就是我自己的想法。

我会将UserUserRepository类的创建放在工厂中

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)
    }
}

这似乎有点矫枉过正(它可能是),但它允许你很容易地重构你的代码,这有利于长期应用。

我想这完全取决于您是喜欢易于阅读的代码还是易于(快速)编写的代码。

于 2013-04-05T17:20:11.497 回答
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 传递给由 UserRepository 创建的 User 对象?

于 2013-04-04T23:13:17.627 回答