Posted at

interfaceを使おう

More than 5 years have passed since last update.

laravel4でリフレクションを使って簡単に開発出来る様になっているのは皆さんご存知だと思いますが、

よりテストもしやすく開発するのに、interfaceを使いましょう。

interfaceを使う事によって、より安全な拡張性、

(interfaceに沿って実装すれば中身が何であっても自由に拡張出来ます)

入れ替え自由(dependency injection)、など利点が沢山有ります。

では実際にlaravel4でinterfaceで実装して、テストもしやすくしてみます

class CalendarController extends BaseController {

protected $schedule;

/**
* __construct
*/

public function __construct(\Schedule $schedule)
{
$this->schedule = $schedule;
}

public function getIndex()
{
$this->schedule->getSchedule();
}
}

スケジューラー的なアプリケーションを作ってるとします。

現在はDBでしょうか

DBのみでしか実装しない場合はこのままでも大丈夫ですし、

newしている訳ではないので別にインターフェースじゃなくても・・という感じですね

例えばテストする場合はどうしましょうか?

テスト用に何か実装を作らないと・・・、

それもいいですが、もっと楽に簡単にできた方がハッピーです

DBを使ってテストすりゃいいーじゃん!と言われればそれまでなんですが・・

interfaceを使う事により、

テスト時にDBだろうが何だろうが意識せずにすむ様になります

interface ScheduleInterface

{
public function getSchedule();
}

簡単にgetScheduleをかならず実装しなければならないものとします。

これを書く事によって、DBだろうがmongoだろうがredisだろうがなんでも動作は保証されるようになります。

class CalendarController extends BaseController {

protected $schedule;

/**
* __construct
*/

public function __construct(\ScheduleInterface $schedule)
{
$this->schedule = $schedule;
}

public function getIndex()
{
$this->schedule->getSchedule();
}
}

interfaceにして完全に分離してしまいます。

interfaceと実装を結びつけるのはどうしたらいいの?と

そんなときにbindです

App::bind('\ScheduleInterface', '\Schedule');

これで結びつける事ができました。

まだ利点がちょっと分かりにくいかもしれません。

ではそのままでDBを使わずにテストする様にしてみましょう。

class CalendarControllerTest  extends TestCase

{
/**
* __construct
*/

public function setUp()
{
parent::setUp();
App::bind('\ScheduleInterface', '\Schedule\Stub');
}

public function testGetIndex()
{
$this->client->request('GET', '/');
~~
}
}

setUpでテストではDBを使わずにinterfaceで定義したものを実装したstubを使う様にします。

テスト用に何か特別なものを用意したりという必要がなくなりました。

テスト以外でも同様にDBから他のものへ変更しても簡単に対応できます。

interfaceから開発していく様にすればきっとモテるでしょう