Composite パターン

デザインパターンちゃんと勉強をしようと思ったので結城さんの本を 1 つ 1 つ実装してみる。 前回の Strategyからの続き。

「構造に関するパターン」に属する。Composite パターンを用いるとディレクトリとファイルなどのような、木構造を伴う再帰的なデータ構造を表すことができる。

木構造は扱う事が多いからこれは良くお世話になりそう。枝と葉を同じように扱うという所にキモがあるのかなと。

クラス図

Composite PlantUML

自分としての理解・疑問

  • 書籍では Entry クラスにて File と Directory(Dir)を同一視するために add で File だった場合の例外処理を入れているが、同様の仕組みを作る必要が実装だけの場合なかったので未実装にしている。
  • また、Entry に含まれている printList は多重定義されているようだけど、PHP では許されていないので abstract 定義のみにしている。
  • 結局再帰的に呼び出される部分が必要になるので、そこをどう実装していくかも考えるポイントになりそう。
<?php
public function printList(string $prefix = '')
{
    echo "{$prefix}/{$this->toString()}\n";

    $this->directory->rewind(); // カーソルを初期化

    // printListが再帰的に呼び出される
    while ($this->directory->hasNext()) {
        $entry = $this->directory->next();
        $entry->printList($prefix."/".$this->name);
    }
}

その他、ハマった所など以下。

PHP では Directory という名前のクラスが作れない

こ、これはちょっとハマった。 :sob:

もちろん名前空間など使って範囲を絞ってやれば使える。が、Directory クラスが作れない…なんで?とグルグルしてた。今回は名前空間使わずに単純に Directory -> Dir として名前を変えて対応した。

Iterator を使って「DirEntry」を用意

PHP には公式で Iterator のインターフェイスが用意されているようなので、DirEntry というクラスを作って JAVA の ArrayList の代わりにした。

最初から用意されている抽象メソッドは以下のようになってるので同様に実装。

<?php
Iterator extends Traversable {
/* メソッド */
abstract public mixed current ( void )
abstract public scalar key ( void )
abstract public void next ( void )
abstract public void rewind ( void )
abstract public boolean valid ( void )
}

他にも元々用意されている SPL イテレータなるものがあるらしいが、追えてない。ってかここまで使いこなしている人いるのかな… :confounded: FileSitemIterator とかは使えそう。

参考