LoginSignup
5
3

More than 5 years have passed since last update.

依存の再束縛

11日目の記事アプリケーションコンテキストと9日目の@zukimochiさんの記事BEAR.SundayのRouterCollectionに関連した内容です。

Ray.Di 2.0の新機能、依存の再束縛です。
インターフェイスとクラスの接続(束縛)を後から変更することができます。

ユースケース

Before

例えばBEAR.SundayのRouterCollectionの記事では元々

$this->bind(RouterInterface::class)->(WebRouter::class);

と束縛しているのを

$this->bind(RouterInterface::class)->(RouterCollectionProvider::class);

と束縛を上書きして、RouterCollectionProviderではRouterCollectionという以下のように2つのルーターを受け取ってグルグル回していました。


    /**
     * @Inject
     * @Named("auraRouter=aura_router,webRouter=web_router")
     */
    public function __construct(AdapterInterface $auraRouter, AdapterInterface $webRouter)
    {

WebRouterからWebRouterAuraRouterを持つRouterCollectionへと変更です。

After

これを「依存の再束縛」を使って現在束縛されているルーターAuraRouterを持つRouterCollectionへと変更してみます。

まず現在のRouterInterfaceにされている束縛にoriginalと名前をつけます。

$this->rename(RouterInterface::class, 'original');

つぎに新しいルーターを束縛します。

$this->bind(RouterInterface::class)->(RouterCollection::class);

RouterCollectionではAdapterInterfaceoriginalという名前で以前の束縛を利用することができます。オリジナルの束縛が変わってもコードに変更はありません!

    /**
     * @Inject
     * @Named("original")
     */
    public function __construct(AdapterInterface $router)
    {

アプリケーションのデコレーション

cliコンテキストではこの依存の再束縛を使っています。

class CliModule extends AbstractModule
{
    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this->rename(RouterInterface::class, 'original');
        $this->bind(RouterInterface::class)->to(CliRouter::class);
        $this->bind(TransferInterface::class)->to(CliResponder::class);
    }
}

コンソールから入力された値をRouterInterfaceに束縛されてあったルーターに渡します。

class CliRouter implements RouterInterface
{
    private $router;

    /**
     * @Inject
     * @Named("original")
     */
    public function __construct(RouterInterface $router)
    {
        $this->router = $router;
    }

    public function match(array $globals = [])
    {
        list(, $method, $uri) = $globals['argv'];
        $globals = [
            // ...コンソールから受け取った値で$globalsを作成
        ];
        return $this->router->match($globals);
    }
}

まとめ

ルーターインターフェイスに束縛されてルーターをそれが何のルーターであるかを知らずに利用して、コンソールから受け取った引数を渡してインターフェイスにあるメソッドを使って元のルーターを利用しています。元のwebアプリケーションに変更することなしに、コンソールアプリケーションにデコレーションすることができました!

「抽象」は実装の詳細に依存してはならない。実装の詳細が「抽象」に依存すべきである。

この依存性逆転の原則が可能にした機能です。

これが何のルーターであるかを知らずには「実装の詳細に依存してはならない」に対応して、インターフェイスにあるメソッドを使って元のルーターを利用が「実装の詳細が「抽象」に依存すべき」に対応します。

明日は@mackstarさんの「BEARとBDD」です。楽しみにしてます!

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3