Builder
Tweetオブジェクトを生成するときに利用する。生成手順
と生成手段
を分けるパターン。
引数が多いオブジェクトの生成や、生成までの手順が複雑なオブジェクトを生成するとき
処理が長くなりやすいので、生成手順
と生成手段
の責任
を分けることができるのが利点
例
チャットメッセージのオブジェクトを生成する。
チャットメッセージを構成する要素は、ユーザ情報とメッセージである。
UML
重要なところ
生成手段
をinterfaceとして定義して、Directorが生成手段
に依存する。
また、このとき生成手順
をDirectorに実装する。
生成手順
の詳細を実装する
これで、
- 生成手順(MessageDirector)
- 生成手段(AdminMessageBuilder)
が分離された状態になる。
PHPで書いてみる
MessageBuilder1
2
3
4
5class 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
19class 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に記載する
MessageDirector1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class 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パターンでに分けることで、責任範囲
がはっきりしクラスをうまく切り分けることができる。
ChatMessage1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class 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};
}
}
User1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class 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 Code1
2
3
4
5$builder = new AdminMessageBuilder();
$director = new MessageDirector($builder);
$message = $director->construct('こんにちは');
echo '本文 : '. $message->message;
まとめ
生成手順
と生成手段
を分離する。生成手段
が複雑な場合は責任範囲
が明確なため、うまく切り分けやすい。