デザインパターン

ウェブアプリケーションのコードやプロジェクトを作っていくにはいろんなやりかたがあって、 どんなふうに作るか考え抜くのもありだし適当に作るのもありだ。 でも普通は、一般的なパターンに従うほうがいい。そのほうがコードを管理しやすいし、 他の人にもそのコードを理解してもらいやすくなるからである。

ファクトリー

最も多用されているデザインパターンのひとつが、ファクトリーパターンだ。このパターンでは、 使いたいオブジェクトを生成するだけのクラスを用意する。ファクトリーパターンの例として、 こんなコードを考えてみよう。

<?php
class Automobile
{
    private $vehicleMake;
    private $vehicleModel;

    public function __construct($make, $model)
    {
        $this->vehicleMake = $make;
        $this->vehicleModel = $model;
    }

    public function getMakeAndModel()
    {
        return $this->vehicleMake . ' ' . $this->vehicleModel;
    }
}

class AutomobileFactory
{
    public static function create($make, $model)
    {
        return new Automobile($make, $model);
    }
}

// ファクトリーを使って Automobile オブジェクトを作る
$veyron = AutomobileFactory::create('ブガッティ', 'ヴェイロン');

print_r($veyron->getMakeAndModel()); // 出力は "ブガッティ ヴェイロン"

このコードは、ファクトリーパターンを使って Automobile オブジェクトを作る。 こんなふうにするメリットは二つある。 まず、もし後で Automobile クラスに手を入れたり名前を変更したり別のものに入れ替えたりすることになっても簡単にできるということ。 単にファクトリーの中のコードを変更すれば済むわけで、 コードの中で Automobile クラスを使っているところをひとつひとつ修正するとかいうことはしなくてもよい。 二番目のメリットは、仮にオブジェクトの生成が複雑な作業になってしまっても、 そのすべてのファクトリーに閉じ込めてしまえること。 新しいインスタンスを作るたびに毎回同じようなことを繰り返さずに済む。

なにがなんでもファクトリーパターンを使えばいいってわけではない。 この例のコードはとてもシンプルだし、この程度だとファクトリーパターンのおかげで 無駄に複雑になったように見えるかもしれない。 でも、それなりに大規模で込み入ったプロジェクトにかかわる場合は、 変なトラブルに巻き込まれないためにもファクトリーを使っておいたほうがいいだろう。

シングルトン

ウェブアプリケーションを設計するときには、概念的そして構造的に、 特定のクラスのたったひとつのインスタンスにだけアクセスさせるようにしたいということがよくある。 そんなときに使えるのがシングルトンパターンだ。

TODO: NEED NEW SINGLETON CODE EXAMPLE

このコードは、静的 な変数getInstance()メソッドを使ってシングルトンパターンを実装している。 これらのことに注目しよう。

シングルトンパターンが有用なのは、たとえばウェブアプリケーションのリクエスト全体で、 たったひとつのインスタンスだけしかないことを保証しないといけない場合だ。 Configurationクラスみたいなグローバルオブジェクトを使っていたり、 イベントキューみたいな共有リソースを使っていたりする場合に活用できる。

ただ、シングルトンを使うときには注意が必要だ。その性質上、シングルトンパターンを使うと アプリケーションにグローバルな状態を導入することになってしまい、テストがしにくくなる。 シングルトンを使いたいという場面では、たいていの場合は依存性の注入が代わりに使える (し、むしろそっちを使うべきだ)。依存性の注入を使えば、不要な結合を アプリケーションの設計から取り除ける。というのも、共有リソースやグローバルリソースを使う オブジェクトが具象クラスについて知らなくてもよくなるからだ。

ストラテジー

ストラテジーパターンを使うと、一連のアルゴリズム群をカプセル化して、 クライアントクラス側から特定のアルゴリズムのインスタンスを作れるようになる。 このときに、実際の実装に関する知識はなくてもかまわない。 このパターンにはいくつかのバリエーションがあるけれど、ここでは一番シンプルなものを解説する。

最初に示すのは、アルゴリズム群を表すコード片だ。 シリアライズした配列、JSON、あるいは単なるデータの配列が欲しいとしよう。

<?php

interface OutputInterface
{
    public function load();
}

class SerializedArrayOutput implements OutputInterface
{
    public function load()
    {
        return serialize($arrayOfData);
    }
}

class JsonStringOutput implements OutputInterface
{
    public function load()
    {
        return json_encode($arrayOfData);
    }
}

class ArrayOutput implements OutputInterface
{
    public function load()
    {
        return $arrayOfData;
    }
}

このようにアルゴリズム群をカプセル化しておけば、使う側のコードからもうまい具合に使えるようになる。 また、他の開発者が新たな出力形式を追加したとしても、使う側のコードは変更する必要がない。

個々の具象「出力」クラスがOutputInterfaceを実装していることに気づくだろう。 その目的は二つ。まずは、具象実装が従うべきシンプルな規約をあてはめること。 そしてもう一つは、このように共通のインターフェイスを実装することで、 次のセクションで説明する タイプヒンティング が使え、正しい型(この場合は’OutputInterface’)を使っていることを保証できるということだ。

次のコードは、呼び出し側のクライアントクラスが実際に特定のアルゴリズムを使ったり、 必要な振る舞いを実行時に設定したりするものだ。

<?php
class SomeClient
{
    private $output;

    public function setOutput(OutputInterface $outputType)
    {
        $this->output = $outputType;
    }

    public function loadOutput()
    {
        return $this->output->load();
    }
}

このクライアントクラスにはprivateなプロパティが用意されている。 実行時には、必ず’OutputInterface’型を設定しておく必要がある。 このプロパティを設定すれば、loadOutput()を呼んだときに、 指定した型の具象クラスのload()メソッドが呼ばれることになる。

<?php
$client = new SomeClient();

// 配列が使いたければ
$client->setOutput(new ArrayOutput());
$data = $client->loadOutput();

// JSONが使いたければ
$client->setOutput(new JsonStringOutput());
$data = $client->loadOutput();

フロントコントローラ

フロントコントローラパターンは、ウェブアプリケーションのエントリポイントをひとつだけ (例: index.php) にして そこですべてのリクエストを処理するというパターンだ。このエントリポイントが、 依存情報を読み込んだりリクエストを処理したりレスポンスをブラウザに返したりといった責務を負う。 フロントコントローラを利用すると、コードのモジュール化が進めやすくなる。 また、すべてのリクエストに対して実行したいコード (入力のチェックなど) をフックとして組み込みやすくなる。

Model-View-Controller

モデル=ビュー=コントローラ (MVC) パターン、そしてその関連パターンである HMVC や MVVM を使うと、コードを論理的に分解してそれぞれ特定の役割を担わせることができる。 モデルはデータアクセス層を扱い、データを取得してそれをアプリケーションで使いやすい形式で返す。 コントローラはリクエストを扱い、モデルから受け取ったデータを処理してビューを読み込み、 それをレスポンスとして返す。 ビューはテンプレート (マークアップや xml など) を扱い、これをレスポンスとしてウェブブラウザに返す。

MVC は最も一般的なアーキテクチャパターンで、主要な PHP フレームワーク でも採用されている。

MVC やその関連パターンについてさらに知りたければ、これらを参考にしよう。