Bridge パターンとは
「橋渡し」のクラスを用意することによって、クラスを複数の方向に拡張させることを目的とする。
Bridge パターン - Wikipedia
この「橋渡し」をする場所は、「機能のクラス階層」と「実装のクラス階層」である。
機能のクラス階層
新しい「機能」を追加したい場合、以下のような階層となる。
SomethingClass
└ ChildSomethingClass
└ GrandChildSomethingClass
実装のクラス階層
新しい「実装」を追加したい場合、以下のような階層となる。
SomethingAbstractClass
└ ConcreteClass
└ ConcreteClass2
example
以下のサンプルコードは「何かを表示」するためのもの。
DisplyaImpl 抽象クラス
<?php
abstract class DisplayImpl
{
abstract public function rawOpen();
abstract public function rawPrint();
abstract public function rawClose();
}
Display クラス
<?php
class Display
{
private $impl;
public function __construct(DisplayImpl $impl)
{
$this->impl = $impl;
}
public function open()
{
$this->impl->rawOpen();
}
public function print()
{
$this->impl->rawPrint();
}
public function close()
{
$this->impl->rawClose();
}
final public function display()
{
$this->open();
$this->print();
$this->close();
}
}
CountDisplayクラス
<?php
class CountDisplay extends Display
{
public function __construct(DisplayImpl $impl)
{
parent::__construct($impl);
}
public function multiDisplay(int $times)
{
$this->open();
for ($i = 0; $i < $times; $i++) {
$this->print();
}
$this->close();
}
}
StringDisplayImplクラス
<?php
class StringDisplayImpl extends DisplayImpl
{
private $string;
private $width;
public function stringDisplayImpl(string $string)
{
$this->string = $string;
$this->width = strlen($string);
}
public function rawOpen()
{
$this->printLine();
}
public function rawPrint()
{
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;
}
}
Main
<?php
$d1 = new Display(new StringDisplayImpl("Hello, Japan."));
$d2 = new CountDisplay(new StringDisplayImpl("Hello, World."));
$d3 = new CountDisplay(new StringDisplayImpl("Hello, Universe."));
$d1->display();
$d2->display();
$d3->display();
$d3->multiDisplay(5);
実行結果
$ php Main.php
+-------------+
|Hello, Japan.|
+-------------+
+-------------+
|Hello, World.|
+-------------+
+----------------+
|Hello, Universe.|
+----------------+
+----------------+
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
+----------------+
github.com
役割
- Abstraction: 機能クラス階層の最上位クラス。Displayクラス
- FefinedAbstraction: 改善した抽象化の役。CountDisplayクラス
- Implementor: 実装者。実装のクラス階層の最上位クラス。DisplayImplクラス。
- ConcreteImplementor: 具体的な実装者。StringDisplayImplクラス。
まとめ
Bridgeパターンの特徴は「機能のクラス階層」と「実装のクラス階層」を分けている点。この2つのクラス階層を分けておけば、それぞれのクラス階層を独立に拡張できる。機能を追加したければ機能のクラス階層にクラスを追加する。このとき、実装のクラス階層は修正する必要がない。さらに、追加した機能は「すべての実装」で利用できる。
例として、OS依存の部分があるプログラムにBridgeパターンを適用することを考える。そのOS依存の部分をBridgeパターンの「実装のクラス階層」で表現し、各OS共通部分のインターフェースを決めてImplementor役とし、ConcreteImplementor役として各OS(win, mac, linuxなど)それぞれのクラスを作る。こうすることによって、「機能のクラス階層」側でいくら機能を追加しても、各OS同時に対応していることになる。
2種類のクラス階層に分離することで、クラス拡張を見通しよく行うことができる。
関連パターン