PHP7でデザインパターン入門7/23 Builderパターン

Builder パターンとは

オブジェクトの生成過程を抽象化することによって、動的なオブジェクトの生成を可能にする。

Builder パターン - Wikipedia

example

以下は、Builderパターンで文書を作成するサンプルプログラム。

Builder 抽象クラス

<?php
abstract class Builder
{
    abstract public function makeTitle(string $title);
    abstract public function makeString(string $str);
    abstract public function makeItems(array $items);
    abstract public function close();
}

Director クラス

<?php
class Director
{
    private $builder;

    public function __construct(Builder $builder)
    {
        $this->builder = $builder;
    }

    public function create()
    {
        $this->builder->makeTitle("Greeting");
        $this->builder->makeString("朝から昼にかけて");
        $this->builder->makeItems([
            "おはようございます。",
            "こんにちは。",
        ]);
        $this->builder->makeString("夜に");
        $this->builder->makeItems([
            "こんばんは。",
            "おやすみなさい。",
            "さようなら。",
        ]);
        $this->builder->close();
    }
}

HTMLBuilder クラス

<?php
class HTMLBuilder extends Builder
{
    private $filename;
    private $writer;

    public function makeTitle(string $title)
    {
        $this->filename = $title . ".html";

        try {
            $this->writer = fopen($this->filename, 'w');
        } catch (Exception $e) {
            $e->getTrace();
        }

        $this->write("<html><head><title>" . $title . "</title></head><body>");
        $this->write("<h1>" . $title . "</h1>");
    }

    public function makeString(string $str)
    {
        $this->write("<p>" . $str . "</p>");
    }

    public function makeItems(array $items)
    {
        $this->write("<ul>");
        for ($i = 0; $i < count($items); $i++) {
            $this->write("<li>" . $items[$i] . "</li>");
        }
        $this->write("</ul>");
    }

    public function write(string $str)
    {
        fwrite($this->writer, $str . PHP_EOL);
    }

    public function close()
    {
        $this->write("</body></html>");
        fclose($this->writer);
    }

    public function getResult(): string
    {
        return $this->filename;
    }
}

TextBuilder クラス

<?php
class TextBuilder extends Builder
{
    private $buffer = "";

    public function makeTitle(string $title)
    {
        $this->append("==============================\n");
        $this->append("" . $title . "\n");
        $this->append(PHP_EOL);
    }

    public function makeString(string $str)
    {
        $this->append('' . $str . PHP_EOL);
        $this->append(PHP_EOL);
    }

    public function makeItems(array $items)
    {
        for ($i = 0; $i < count($items); $i++) {
            $this->append(" ・" . $items[$i] . PHP_EOL);
        }
        $this->append(PHP_EOL);
    }

    public function close()
    {
        $this->append("==============================\n");
    }

    public function getResult(): string
    {
        return $this->buffer;
    }

    public function append(string $str)
    {
        $this->buffer .= $str;
    }
}

Main

<?php
echo "1:plain, 2:html :";

$input = intval(trim(fgets(STDIN)));
if ($input === 1) {
    $textbuilder = new TextBuilder();
    $director = new Director($textbuilder);
    $director->create();
    $result = $textbuilder->getResult();
    echo $result;
} elseif ($input === 2) {
    $htmlbuilder = new HTMLBuilder();
    $director = new Director($htmlbuilder);
    $director->create();
    $filename = $htmlbuilder->getResult();
    echo $filename . "が作成されました。";
} else {
    usage();
    exit;
}

function usage()
{
    echo "Usage: plain プレーンテキストで文書作成";
    echo PHP_EOL;
    echo "Usage: html HTMLファイルで文書作成";
}

実行結果1

$ php Main.php
1:plain, 2:html :1
==============================
『Greeting』

■朝から昼にかけて

 ・おはようございます。
 ・こんにちは。

■夜に

 ・こんばんは。
 ・おやすみなさい。
 ・さようなら。

==============================

実行結果2

$ php Main.php
1:plain, 2:html :2
Greeting.htmlが作成されました。#

ソースコード

github.com

役割

  • Builder: インスタンス生成のためのインターフェースを定める。サンプルではBuilderクラス。
  • ConcreteBuilder: Builder役のインターフェースを実装するクラス。サンプルではTextBuilder,HTMLBuilderクラス。
  • Director: Builder役のインターフェースを使ってインスタンスを生成する役割。Builder役のメソッドのみを利用すr。サンプルではDirectorクラス。

まとめ

  • オブジェクト指向プログラミンでは「誰が何を知っているか」がとても重要。
  • 何を利用しているか「知らない」ということは、「入れ替え可能」ということ。交換可能性(入れ替えができるかどうか)は常に意識して設計を行う必要がある。

関連パターン

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門