Laravelの契約とDIとStrategyパターン

著者:杉浦

Laravelの契約とDIとStrategyパターン

 あるフレームワークを対象にしたライブラリというものはフレームワーク内のある機能を拡張したり、まるで違う中身で似た役割を果たす、といったものが少なくありません。その様なことをしても不具合を起きにくくするためにinterfaceの仕組みを用います。Laravelでは契約という名でまとめられています。
契約 5.8 Laravel
 例えばハッシュ処理なら次です。
 contracts/Hasher.php at 5.8 · illuminate/contracts

<?php
namespace Illuminate\Contracts\Hashing;
interface Hasher
{
    /**
     * Get information about the given hashed value.
     *
     * @param  string  $hashedValue
     * @return array
     */
    public function info($hashedValue);
    /**
     * Hash the given value.
     *
     * @param  string  $value
     * @param  array   $options
     * @return string
     */
    public function make($value, array $options = []);
    /**
     * Check the given plain value against a hash.
     *
     * @param  string  $value
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function check($value, $hashedValue, array $options = []);
    /**
     * Check if the given hash has been hashed using the given options.
     *
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function needsRehash($hashedValue, array $options = []);
}

 ハッシュ処理用の機能を作るならば、このインターフェースを実装しなさい、という契約です。Laravelの内部機能でハッシュ処理を行う際はこの契約によって作られることが保証されたメソッドのみを呼び出します。
 機能ができたならばどうにかそれを適用する必要があります。DI(依存性注入)というやり方によってこれを容易にします。依存性注入とはあるクラスへの依存を既に存在しているインスタンスや今まさに作られるインスタンスに注入するようなものです。例えば、次です。

<?php

namespace App\Http\Controllers;

use App\User;
use App\Repositories\UserRepository;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * ユーザーリポジトリの実装
     *
     * @var UserRepository
     */
    protected $users;

    /**
     * 新しいコントローラインスタンスの生成
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }

    /**
     * 指定ユーザーのプロフィール表示
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        $user = $this->users->find($id);

        return view('user.profile', ['user' => $user]);
    }
}
<a href="https://readouble.com/laravel/5.8/ja/container.html">サービスコンテナ 5.8 Laravel</a>より引用

 __construct(UserRepository $users)の部分でUserControllerクラスのインスタンスの持つプロパティであるusersはUserRepositoryインターフェースという契約を満たすことを強制されています。UserRepositoryインターフェースには必ずfindメソッドが実装する契約が記述されています。このため

        $user = $this->users->find($id);

 の部分は決して未定義エラーにならず、UserRepositoryを満たした何らかのクラスのインスタンスusers独自のfindメソッド処理を働かせます。
 DIは、ある目的を達成するためのアルゴリズムをごっそり代えることを容易にするプログラミングパターンであるStrategyパターンそのものです。既にDIを用いている部分は後から好き勝手コードを追加、変更したとしても注入口の記述を変えるだけで簡単にバグなく動かせます。

  • この記事いいね! (1)

著者について

杉浦 administrator