「何を行うのか(機能)」と「どのような処理をするのか(実装)」それぞれの拡張方法を分けるパターン。

「何を行うのか(機能)」を実装する場合は、「どのような処理をするのか(実装)」を意識しなくても良いのが利点。

Bridgeパターンは先日のAdapter パターンと非常によく似ているが、
Adapterパターンは既存のクラスを再利用するために導入する後天的な理由に対し、
Bridgeパターンは設計の段階で分離するという先天的な理由で導入されるのが大きな違い。

また、よくOOPを学び始めにやりがちな継承の失敗(is-a関係から外れた継承)を起こしにくいので積極的に導入したい。

XMLかHTML5からタイトルを取得する。

UML

重要なところ

どのような処理をするのかを実装する。

何を行うのかを実装する。

これで、

  • 何を行うのか(WebScraper)
  • どのような処理をするのか(PageParser,DOMParser,XPathParser)

が分離された状態になる。

PHPで書いてみる

PageParser

1
2
3
4
interface PageParser
{
public function getTitle() : string;
}

DOMParser

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class DOMParser implements PageParser
{
prviate $document;

public function __construct(DOMDocument $document)
{
$this->document = $document;
}

public function getTitle() : string
{
$element = $this->document->getElementsByTagName('title')->item(0);

return $element->textContent ?? '';
}
}

DOMParserがどのような処理をするのかを表している。
この例ではDOMDocumentを取得して、titleタグの1つ目のテキストを取得している。

WebScraper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class WebScraper
{
protected $pageParser;

public function __construct(PageParser $pageParser)
{
// このクラスはどのように処理するのかを委譲している
$this->pageParser = $pageParser;
}

public function getTitle() : string
{
return $this->pageSource->getTitle();
}
}

WebScraperが何をするのかのコード。

WebScraperは、PageParserクラスをプロパティで保持して、
具体的にgetTitleでどのような処理をするのかをPageParserに委譲している。

このようにWebScraperが何をするのかどのように処理するのか橋渡しをしている。

ここでタイトルの一部分だけを取得する機能が拡張された場合でも

1
2
3
4
5
6
7
class HyperWebScraper extends WebScraper
{
public function getSubstringTitle(int $start, int $end) : string
{
return substr($this->pageSource->getTitle(), $start, $end);
}
}

このように何をするのかは具体的なタイトルを取得する処理を知ることなく実装することができる。

Client Code

1
2
3
4
5
6
7
8

$doc = new DOMDocument();
$doc->loadHTMLFile('example.html');

$pageSource = new DOMParser($doc);
$webScraper = new WebScraper($pageSource);

echo $webScraper->getTitle();

まとめ

  1. 何を行うのかどのような処理をするのかを分離する。
  2. 何を行うのかを実装する場合は、どのような処理をするのかを意識しなくても良い。
  3. 委譲で実装する。

参考

WikiPedia
Do You PHP はてな