読者です 読者をやめる 読者になる 読者になる

Commandパターン

perl

命令(Command)をメソッド呼び出しではなくて、オブジェクトとして実装するパターン。通常は命令したい内容に応じてメソッド引数を変えるが、Commandパターンはオブジェクトを渡す。

メリット
  1. 命令そのものに情報を持たせることができる
  2. 複数の命令を呼び出し側が組み合わせできる
  3. 命令の集合をつくることができる
使用例
  • アプリケーションのredo/undo(実行したオブジェクトを保持)
  • 総実行時間の予測(各Commandオブジェクトが予測時間を持つ)
  • 非同期キュー処理(Commandオブジェクトを一旦保存して、リモート/別プロセス実行)
簡単な実装

足し算と引き算をCommandパターンで実装してみる(実にくだらないけど)

  • Commandクラス
package Command;

sub new {
    my ($class, $ref_hash) = @_;
    return bless({ calc => $ref_hash }, $class);
}
sub execute { die; }
1;
  • Command::Plusクラス
package Command::Plus;
use base qw(Command);
sub execute {
    my ($self, $val) = @_;
    $self->{calc}{value} += $val;
    push(@{$self->{calc}{exec_log}}, "add val($val).");
}
1;
  • Command::Minusクラス
package Command::Minus;
use base qw(Command);
sub execute {
    my ($self, $val) = @_;
    $self->{calc}{value} -= $val;
    push(@{$self->{calc}{exec_log}}, "minus val($val).");
}
1;
  • mainプログラム
use Command;
use Command::Plus;
use Command::Minus;

my %calc = (
    value    => 0,
    exec_log => [],
);

my $plus  = new Command::Plus(\%calc);
my $minus = new Command::Minus(\%calc);

$plus->execute(1);  # 1
$plus->execute(4);  # 5 
$minus->execute(2); # 3

printf("value is %d\n", $calc{value});
printf("%s\n", join("\n", @{$calc{exec_log}}));
  • 結果
value is 3
add val(1).
add val(4).
minus val(2).
まとめ
  • Commandパターンはメソッド呼び出しに比べて、実装は手間。
  • ただ、履歴を残す/命令の集合をつくれる等、再利用性がぐっと高まることが大きなメリット。