3

これは言語に依存しない質問ですが、PHP でサンプル コードを記述します。

2 つのクラスがあります。

  1. ユーザークラス
  2. UserRepositoryクラス

UserRepository クラスは、DB とのやり取りを処理し、必要な User を User オブジェクトにロードして返します。

User クラス内に、そもそもロードされないメール属性があり、必要なときにいつでもデータベースから遅延ロードされるとします。ただし、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;
    }
} 

EmailProxy クラス

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

私の質問は、UserRepositoryによって作成されたUserオブジェクトにEmailProxyを渡す方法です。

  • UserProxy インスタンスを UserRepository に注入して、新しく作成された User オブジェクトに注入できるようにしますか?

  • これに依存性注入コンテナーを使用しますか?

  • 工場を利用しますか?

編集

EmailProxyはすでにUserRepository を認識しています。EmailProxyUserRepositoryにも渡すと、循環依存になります。

コード/コメントをいただければ幸いです。

ありがとう、

4

2 に答える 2

1

これは難しい質問であり、人々がどのように対処しているかを知りたいです。そんな中、ふと思いついたのがこちら。

UserUserRepositoryクラスの作成を Factory に入れます

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

しかし、それはあまりにも明白な答えのように思えます。投稿されているものとはまったく異なることを求めているのではないかと思います。あなたの質問を言い換えることができます:

私の質問は、 UserRepository によって作成された User オブジェクトに EmailProxy を渡す方法です。

于 2013-04-04T23:13:17.627 に答える