本記事に掲載したサンプルコードは、https://github.com/ryo-utsunomiya/design_patternでも公開中です。
Bridgeとは
「機能」のクラス階層と「実装」のクラス階層を分離し、それらを独立に変更できるようにすることです。
これによって、「機能」を柔軟に交換できるようになります。
まず、「何かを表示する」という「機能」を持ったDisplay
クラスを作成してみます。
<?php
namespace Bridge;
class Display
{
/**
* @var DisplayImpl
*/
private $impl;
/**
* Display constructor.
*
* @param DisplayImpl $impl
*/
public function __construct(DisplayImpl $impl)
{
$this->impl = $impl;
}
public function open()
{
$this->impl->rawOpen();
}
public function show()
{
$this->impl->rawShow();
}
public function close()
{
$this->impl->rawClose();
}
public function display()
{
$this->open();
$this->show();
$this->close();
}
}
このクラスは「何かを表示する」機能の具体的な実装であるDisplayImpl
に依存しています。DisplayImpl
は、実装を交換可能にするため抽象クラスにします。
<?php
namespace Bridge;
abstract class DisplayImpl
{
public abstract function rawOpen();
public abstract function rawShow();
public abstract function rawClose();
}
次に、DisplayImpl
の具象クラスであるStringDisplayImpl
を実装してみます。
<?php
namespace Bridge;
class StringDisplayImpl extends DisplayImpl
{
/**
* @var string
*/
private $string;
/**
* @var int
*/
private $width;
/**
* StringDisplayImpl constructor.
*
* @param string $string
*/
public function __construct($string)
{
$this->string = $string;
$this->width = mb_strlen($string);
}
public function rawOpen()
{
$this->printLine();
}
public function rawShow()
{
echo '|' . $this->string . '|' . PHP_EOL;
}
public function rawClose()
{
$this->printLine();
}
private function printLine()
{
echo '+';
for ($i = 0; $i < $this->width; $i++) {
echo '-';
}
echo '+' . PHP_EOL;
}
}
StringDisplayImpl
では、文字列を装飾して表示します。StringDisplayImpl
を変更しなくても、DisplayImpl
のサブクラスを作れば、表示方法を変更することができます。
次に、表示する「機能」の方を変更してみます。
<?php
namespace Bridge;
class CountDisplay extends Display
{
/**
* CountDisplay constructor.
*
* @param DisplayImpl $impl
*/
public function __construct(DisplayImpl $impl)
{
parent::__construct($impl);
}
/**
* @param int $times
*/
public function multiDisplay($times)
{
$this->open();
for ($i = 0, $times = (int)$times; $i < $times; $i++) {
$this->show();
}
$this->close();
}
}
CountDisplay
は、Display
を拡張し、同じ文言を複数回表示するmultiDisplay
メソッドを追加しています。
最後に、これらのクラスの使用例です。
<?php
namespace Bridge;
require_once __DIR__ . '/../autoload.php';
$d1 = new Display(new StringDisplayImpl('Hello, Japan'));
$d2 = new CountDisplay(new StringDisplayImpl('Hello, World'));
$d1->display();
$d2->display();
$d2->multiDisplay(3);
このように、機能と実装を分離することで、機能・実装の両方を柔軟に交換可能にするのがBridge
パターンの特長です。