forget for get

覚えるために忘れる

Bridgeパターン

機能の階層と実装の階層を分ける

機能(メソッド)を追加したいとき、サブクラス(子クラス、派生クラス、拡張クラス)をつくる
さらに機能を追加する場合、さらに階層が深くなる

Something
  SomethingGood
    SomethingBetter

抽象クラスでインタフェース(API)を規定し、サブクラスで実装する。
部品として交換しやすいクラスになる。

AbstractClass
  ConcreteClass1
  ConcreteClass2

機能の階層と実装の階層が混在していると見通しが悪いので分ける。

Abstraction(抽象化):Display
機能クラス階層の最上位。
Implementorを保持し、そのメソッドを使って機能を記述。

RefinedAbstraction(改善した抽象化):CountDisplay
Abstractionに機能を追加したもの。

Implementor(実装者):DisplayImpl
実装クラス階層の最上位。
Abstractionのインタフェースを実装するためのメソッドを規定。

ConcreteImplementor(具体的な実装者):StringDisplayImpl
Implementorを実装。

2つの階層を$implが橋渡ししている。
分けておけば拡張するのが楽になる。

継承だとソースコードを書き換えないと変わらない。
Displayのように、委譲すると、引数で渡すものを変えれば変わる。

Display.php

class Display {
  private $impl;
  function __construct(DisplayImpl $impl) {
    $this->impl = $impl;
  }
  function open() {
    $this->impl->rawOpen();
  }
  function print() {
    $this->impl->rawPrint();
  }
  function close() {
    $this->impl->rawClose();
  }
  final function display() {
    $this->open();
    $this->print();
    $this->close();
  }
}

CountDisplay.php

class CountDisplay extends Display {
  function __construct(DisplayImpl $impl) {
    parent::__construct($impl);
  }
  function multiDisplay($times) {
    $this->open();
    for ($i=0;$i<$times;$i++) {
      $this->print();
    }
    $this->close();
  }
}

DisplayImpl.php

abstract class DisplayImpl {
  abstract function rawOpen();
  abstract function rawPrint();
  abstract function rawClose();
}

StringDisplayImpl.php

class StringDisplayImpl extends DisplayImpl {
  private $string;
  private $width;
  function __construct($string) {
    $this->string = $string;
    $this->width = strlen($string);
  }
  function rawOpen() {
    $this->printLine();
  }
  function rawPrint() {
    echo "|" . $this->string . "|\n";
  }
  function rawClose() {
    $this->printLine();
  }
  private function printLine() {
    echo "+";
    for ($i=0;$i<$this->width;$i++) {
      echo "-";
    }
    echo "+\n";
  }
}

Main.php

require "../autoload.php";
$d1 = new Display(new StringDisplayImpl("Hello"));
$d2 = new CountDisplay(new StringDisplayImpl("Good bye"));
$d3 = new CountDisplay(new StringDisplayImpl("Good night"));
$d1->display();
$d2->display();
$d3->display();
$d3->multiDisplay(3);