概要

コマンド(要求)をオブジェクトとしてカプセル化し、
要求要求の受付要求の対応を分離してするパターン。

利点

  • 要求要求の受付要求の対応を別々で考えて実装できるので、要求が追加されるパターンに強い。
  • 要求の対応が独立していて、再利用性が高い。

料金計算の割引コマンドを実装する

UML

重要なところ

要求を実装する。

この時、要求は、抽象クラスと具象クラスで実装する。

要求の受付を実装する。

実装するコマンドは要求の抽象クラスへ依存させる。

PHPで書いてみる

要求の抽象クラス

1
2
3
4
5
6
7
8
9
10
abstract class DiscountCommand {
protected $price;

public function __construct(Price $price)
{
$this->price = $price;
}

abstract public function discount() : void;
}

要求の具象クラス

1
2
3
4
5
6
class HalfDiscountCommand extends DiscountCommand {
public function discount() : void
{
$this->price->discount(round($this->price->get() / 2));
}
}

1
2
3
4
5
6
class TaxDiscountCommand extends DiscountCommand {
public function discount() : void
{
$this->price->discount($this->price->getTax());
}
}

要求の受付の実装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class DiscountCommandInvoker {
private $commands = [];

public function setCommand(DiscountCommand $command) // 抽象に依存させる
{
$this->commands[] = $command;
}

public function run()
{
foreach ($this->commands as $command)
{
$command->discount();
}
}
}

要求の対応の実装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Price {
private $price;

public function __construct(int $price) // 抽象に依存させる
{
$this->price = $price;
}

public function get() : int
{
return $this->price;
}

public function getTax() : int
{
return $this->price - floor($this->price / 1.08);
}

public function discount(int $price)
{
$this->price = $this->price - $price;
}
}

Client Code

1
2
3
4
5
6
7
$price = new Price(216);
$invoker = new DiscountCommandInvoker();
$invoker->setCommand(new TaxDiscountCommand($price));
$invoker->setCommand(new HalfDiscountCommand($price));

$invoker->run();
echo $price->get() . '円';

これで、完全に要求要求の受付要求の対応が分離された。
また、要求の対応が独立していて再利用が非常にしやすい。

割引種別が増えた場合でも、setCommandを利用して新しい割引種別を追加するだけで割引金額を求めることができる。

まとめ

  1. 要求要求の受付要求の対応を分離する。
  2. 要求の受付要求の抽象に依存し、要求要求の対応に依存する。

参考

WikiPedia
Java本格入門