【PHPデザインパターン】08_Bridge~実装と機能の架け橋


引用記事

この記事を書くきっかけになったブログです。

記事内の解説やソースコードは、こちらのブログと著者の公開リポジトリを参考にしています。

Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Bridge~実装と機能の架け橋

概要

  • 「何をするのか」と「どうやって実現するのか」分けて考え、これらを結びつけるための橋を用意する。
  • 抽出されたクラス(何をするのか)と実装(どうやって実現するのか)を分離して、それらを独立に変更できるようにする。

構成要素

Abstractionクラス

  • 「何をするのか」を実現するクラス群で最上位に位置するクラス。
  • Implementorオブジェクトを保持する。
  • Implementorクラスが提供する機能をクライアントに提供する。

RefinedAbstractionクラス

  • Abstractionクラスで提供される機能を拡張するサブクラス。

Implementorクラス

  • 「どうやってするのか」を実現するクラス群で最上位に位置するクラス。
  • インターフェースとして実装される場合もある。
  • Abstractionクラスで提供しているAPIに一致する必要はない。

ConcreteImplementorクラス

  • Implementorクラスのサブクラス。
  • 具体的な実装を行う。

実演

処理の流れ

  • 配列をコンマ区切りの文字列として返す。
  • 拡張クラスではタブ区切りの文字列として返す。

ファイル構造

MyBridge
  ├── ArrayDatasource.php
  ├── Datasource.php
  ├── Listing.php
  ├── TabListing.php
  └── my_client.php

ソースコード

Abstractionクラス

Listing.php

Listing.php
<?php
namespace DoYouPhp\PhpDesignPattern\Bridge\MyBridge;

use DoYouPhp\PhpDesignPattern\Bridge\MyBridge\DataSource;

// Abstractionクラスに相当する
class Listing
{
    private $data_source;

    // コンストラクタ
    // DataSourceオブジェクトをプロパティとしてセットする
    public function __construct(DataSource $data_source)
    {
        $this->data_source = $data_source;
    }

    // readメソッドはDataSourceオブジェクトのメソッド
    // readメソッドはArrayDataSourceクラスで実装されている
    // 受け取った配列型プロパティをコンマ区切りの文字列として出力する
    public function read()
    {
        return $this->data_source->read();
    }
}

RefinedAbstractionクラス

TabListing.php

TabListing.php
<?php
namespace DoYouPhp\PhpDesignPattern\Bridge\MyBridge;

use DoYouPhp\PhpDesignPattern\Bridge\MyBridge\Listing;

// RefinedAbstractionクラスに相当する
// Listingクラスの拡張クラス
class TabListing extends Listing
{
    // 親クラスのコンストラクタを利用する
    // DataSourceオブジェクトをプロパティとしてセットする
    public function __construct($data_source)
    {
        parent::__construct($data_source);
    }

    // readメソッドはListingクラスで実装されているDataSourceオブジェクトのメソッド
    // 元をたどると、readメソッドはArrayDataSourceクラスで実装されている
    // 受け取った文字列をタブ区切りに変更する
    public function readWithTab()
    {
        return str_replace(',', "\t", $this->read());
    }
}

Implementorクラス

Datasource.php

Datasource.php
<?php
namespace DoYouPhp\PhpDesignPattern\Bridge\MyBridge;

// Implementorクラスに相当する
// インターフェイスのため、メソッドはサブクラスで実装する
interface DataSource
{
    public function read();
}

ConcreteImplementorクラス

ArrayDatasource.php

ArrayDatasource.php
<?php
namespace DoYouPhp\PhpDesignPattern\Bridge\MyBridge;

use DoYouPhp\PhpDesignPattern\Bridge\MyBridge\DataSource;

// ConcreteImplementorクラスに相当する
// DataSourceクラスのメソッドを実装する
class ArrayDataSource implements DataSource
{
    private $source_name;

    // コンストラクタでデータを配列型プロパティとしてセットする
    public function __construct($source_name)
    {
        $this->source_name = $source_name;
    }

    // 受け取った配列型プロパティをコンマ区切りの文字列として出力する
    public function read()
    {
        $source_string = '';

        foreach ($this->source_name as $value) {
            $source_string .= $value.",";
        }

        return $source_string;
    }
}

Clientクラス

my_client.php

my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Bridge\MyBridge;

require dirname(dirname(__DIR__)).'/vendor/autoload.php';

use DoYouPhp\PhpDesignPattern\Bridge\MyBridge\Listing;
use DoYouPhp\PhpDesignPattern\Bridge\MyBridge\TabListing;
use DoYouPhp\PhpDesignPattern\Bridge\MyBridge\ArrayDataSource;

// Clientクラスに相当する
// データを読み込むDataSourceクラスのオブジェクトを生成する
$data_array = array('apple', 'orange', 'banana'); 
$source = new ArrayDataSource($data_array);

// Listingクラスを使ってデータを表示する
echo 'Listingクラスを使った表示'.'<br>'."\n";
$list = new Listing($source);
$data = $list->read();
echo $data.'<br>'."\n";

// TabListingクラスを使ってデータを表示する
echo 'TabListingクラスを使った表示'.'<br>'."\n";
$list = new TabListing($source);
$data = $list->readWithTab();
echo $data.'<br>'."\n";