オブジェクトを生成するときに利用する。
生成手順生成手段を分けるパターン。

引数が多いオブジェクトの生成や、生成までの手順が複雑なオブジェクトを生成するとき
処理が長くなりやすいので、生成手順生成手段責任を分けることができるのが利点

チャットメッセージのオブジェクトを生成する。
チャットメッセージを構成する要素は、ユーザ情報とメッセージである。

UML

重要なところ

生成手段をinterfaceとして定義して、Directorが生成手段に依存する。
また、このとき生成手順をDirectorに実装する。

生成手順の詳細を実装する

これで、

  • 生成手順(MessageDirector)
  • 生成手段(AdminMessageBuilder)

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

PHPで書いてみる

MessageBuilder

1
2
3
4
5
class MessageBuilder {
public function setMessage(string $message) : void;
public function setUser() : void;
public function getResult() : ChatMessage;
}

AdminMessageBuilder(生成手段)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class AdminMessageBuilder {
private $message;
private $user;

public function setMessage(string $message) : void
{
$this->message = $message;
}

public function setUser() : void
{
$this->user = new User('admin');
}

public function getResult() : ChatMessage
{
return new ChatMessage($this->user, $this->message);
}
}

どのように生成するのか(生成手段)をBuilderに記載する

MessageDirector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MessageDirector
{
private $builder;

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

public function construct(string $message) : ChatMessage
{
// ChatMessageの生成手順のみを記載する。
$this->builder->setMessage($message);
$this->builder->setUser();

return $this->builder->getResult();
}
}

生成手順をDirectorに記載する。
こうすることによって、以下の様になる。

  • Directorはどのように生成するかは知らないが、何を生成するかは知っている。
  • Builderは、自らが知っている手順に従ってオブジェクトの生成を行う。

すると、生成手段が複雑な場合はBuilderパターンでに分けることで、
責任範囲がはっきりしクラスをうまく切り分けることができる。

ChatMessage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class ChatMessage {
private $user;

private $message;

public function __construct(User $user, string $message)
{
$this->user = $user;
$this->message = $message;
}

public function __get($name)
{
if (! property_exists($this, $name)) {
throw new InvalidArgumentException('存在しないPropertyです');
}

return $this->{$name};
}
}

User

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class User {
private $user_role;

public function __construct(string $user_role)
{
$this->user_role = $user_role;
}

public function __get($name)
{
if (! property_exists($this, $name)) {
throw new InvalidArgumentException('存在しないPropertyです');
}

return $this->{$name};
}
}

Client Code

1
2
3
4
5
$builder  = new AdminMessageBuilder();
$director = new MessageDirector($builder);
$message = $director->construct('こんにちは');

echo '本文 : '. $message->message;

まとめ

  1. 生成手順生成手段を分離する。
  2. 生成手段が複雑な場合は責任範囲が明確なため、うまく切り分けやすい。

参考

Wikipedia
Javaで書くBuilderパターンのパターン